DEV Community

TrackMyStories
TrackMyStories

Posted on

Javascript: The four rules of {this}.

Firstly, this article is written with reference to a chapter from Kyle Simpson's great book You Don't Know JS: this & Object Prototypes. It is an incredible resource for anyone looking to build a deeper understanding of Javascript.

What rules determine the order of precedence where this points to when a function is executed?

There are four rules that determine the order of precedence on where this points to during function execution:

• Default Binding
• Implicit Binding
• Explicit Binding
• Hard Binding

Default Binding :

function js(){
 console.log(this.binding);
}
var binding = 'default binding';
js(); // default binding

Breaking down our snippet above and understanding how our call-site determines where this points to when function js(){...} is executed, firstly, function js(){…} is our call-stack which holds console.log(this.binding); and the call-site for our function is js(); which is located on the last line of the snippet which is the point from which the function is called. furthermore, our variable var binding = 'default binding'; is declared in the global scope.

Implicit Binding:

function properties(){
 console.log(this.binding);
}
var object = {
 binding: 'implicit binding',
 properties: properties
};
object.properties(); // implicit binding

If you've worked with apollo resolvers or the react context API this second rule will give some deeper clarity on how they work through javascript.

breaking down the above snippet, our call-stack is function properties(){...}

which holds our this.binding binding, our call-site is object.properties();.

however, what differentiates this rule to the default binding is in the manner in which our call-site is declared.
The implicit rule can be determined if our call-site has a context object, function properties(){...}; is declared in the same fashion as our default binding from our first example, however, our call-site references object when calling a function, object.properties();.

At the point at which properties(); is called it is prefixed with var object = {...}, which contains the value on execution.

reference: As Kyle Simpson states in his book You Don't Know JS: this & Object Prototypes :

"When there is a context object for a function reference, the implicit binding rule says that it's object which should be used for the function call's this binding."

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

Explicit Binding:

function properties(){
 console.log(this.binding);
}
var object = {
 binding : 'explicit binding'
};
properties.call(object); //explicit binding
or
properties.apply(object); //explicit binding
// call or apply produce the same result.

Instead of including an implicit function reference inside var object = {...} and prefixing it to the call-site, we can explicitly call the function with a built-in utility call() and apply(), the function properties(){...} is the call-stack, however, our call-site uses the built-in utility to execute the function explicitly. It is important to note that call() and apply() result in the same outcome unless additional parameters are passed to them.

Hard Binding:

function properties(){
 console.log(this.binding);
}
var object = {
 binding: 'hard binding'
};
var hardBindedPropertiesToObject = function(){
 properties.call(object);
}
hardBindedPropertiesToObject(); // hard binding

With respect to the hard binding snippet above, we create a function var hardBindedPropertiesToObject= function(){//call(object)} which calls the call-stack with var object = {...} which points towards this.

reference: As Kyle Simpson states in his book You Don't Know JS: this & Object Prototypes :

"This binding is both explicit and strong, so we call it hard binding."

Another thing to note is that the hard binding pattern has its own built-in utility Function.prototype.bind().

consider:

const module = {
 x: 42,
 getX: function() {
 return this.x;
 }
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

source MDN developer.mozilla.org states:

To conclude, here are the 4 rules of this , I would highly recommend reading the you dont know js book series by Kyle Simpson. His books cover all the aspects of javascript that can enable any developer to gain proficiency in the language.

Top comments (0)