I am lost with this — JavaScript

Nikhil Kapoor
5 min readAug 11, 2018

--

If you are here , then at some point you may also have lost your “this”…so let’s discuss about it more

Source — Google Images

Table of Content

  1. What is “this” in JavaScript?
  2. Problems with “this”
  3. Four Magical Rules
  4. Playing with arrow function
  5. Conclusion

What is “this” in JavaScript ?

“this ”usually refers to the execution context or In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.

For Example:

function foo () {  return anything; }foo();

In above example “this” or scope will refer to global window that is

this === window // true;

but not in every case. How ? we’ll discuss later.

but till now everything seems fine with “this ”… why everyone howl so much about lost in “this” ? let’s Discuss the problems

Problems with “this”

Use Case 1:

function useCase(name) {
this.myName = name;
function returnMe() {
return this; //scope is lost because of the inner function
}

return {
returnMe : returnMe
}
}
let baz = new useCase('this is lost');
baz.returnMe().myName // undefined

In this use case, we are getting undefined in the end… why ? because of inner function. “returnMe” function is returning its own scope hence we can not get the “myName” variable.

Use Case 2:

function getSomeContent(filePath, callbackFn, scope) {  
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callbackFn.call(scope, xhr.responseText);
}
}
xhr.open("GET", chrome.extension.getURL(filePath), true);
xhr.send();
}
var test = "hey !";

getSomeContent("test.js", function(data) {
alert(test);
});

In this scenario, test will be resolved as you’d expect it, but the value of this might be different. Again… we lost it.

Solution ? before that lets understand the bindings

Four Magical Rules or KS Rules

Thanks to kyle simpson for this. I am a great follower of him, so In his own way, lets discuss about bindings

  • Default Binding
  • Implicit Binding
  • Explicit Binding
  • New Binding

To understand the concept of “this”, forget everything and just remember we have to look only for “call site”. We don’t care about function declaration now.

Default Binding ( First Rule )

function foo() { 
// we passed global execution context with default binding,
this.faz = 'whopiee';
// this is referring to window object hence faz will get declare in global context
this.baz(); //
}
function baz () {
console.log(this.faz); // hence we are referring to same this
}
foo(); // current context is global

our first rule gets applied when we are calling function as standalone function invocation like foo(); in above example

In Above example

Since we are calling with global site scope hence we are using the global scope which is our first rule to understand this

Implicit Binding ( Second Rule )

function bam() {
console.log( this.a );
}

var obj = {
a: 18,
bam: bam
};


obj.bam(); // 18

What to see now ? “Call Site” , call site now says. Hey compiler ! I am giving you the reference. Which is obj , Hence in this case our scope will refer to current object. In above example, our current context is obj hence value of a will be 18. so now if you see the call site with object.function, here we will go with second rule which is implicit binding.

With implicit binding as we just saw, we had to mutate the object in order to include a reference on itself to the function, and use this property function reference to indirectly (implicitly) bind this to the object.

But, what if you want to force a function call to use a particular object for the this binding, without putting a property function reference on the object?

Explicit Binding ( Third Rule )

For the third rule, if you ever see .call() , .bind() or .apply(), Don’t look for anything else it is our explicit binding. These 3 functions are known as function bindings

function baz() {
console.log(this.value);
}

let obj = {
value : 'could be anything'
};

baz.call(obj); // could be anything

calling baz with explicit binding by baz.call(..) allows us to force its this to be obj.

function foo(param) {
return this.value + param;
}
var obj = {
value: 2
};
var baz = function() {
return foo.apply( obj, arguments );
};
var boo = baz(1); // 1 2
console.log(boo); // 3

The most typical way to wrap a function with a hard binding creates a pass-thru of any arguments passed using apply and any return value received.

function baz(param) {
return this.value + param;
}
var obj = {
value: 1
};
var bindFunction = baz.bind(obj);var result = bindFunction(4); // 5

bind(..) will return a new function that is hard-coded to call the original function with the this context set as you specified.

New Binding ( Fourth Rule )

our last rule, So now again go to “call site” and see if we are using constructor pattern or new keyword. Label it as 4th Rule

let baz = new foo(...);

what actually new does in code behind ? so whenever we write our code using new keyword 4 things happen in code behind which is :

  1. A new empty object is created {}
  2. Newly created object gets register to prototype
  3. the newly created object is set as the this binding for that function call
  4. And will automatically return the newly constructed object.

Example ? lets see:

function bam(param) {
this.value = param;
}

var baz = new bam(2);
// above 4 things will happen and this of bam will get return
console.log(baz.value);

In above Example , We’ll get the this/scope of function bam() into baz.

By calling bam(..) with new in front of it, we've created a new object and set that new object as the this for the call of baz(..). So new is the final way that a function call's this can be bound. We'll call this new binding.

In my next article, we will see the magic of arrow function to solve the problem of this

I hope that you’ll like my article. Please praise me with your feedback :)

--

--