Click to share! ⬇️

javascript this keyword explained

Much like nailing jelly to a wall, the this keyword in JavaScript is a bit like a whack-a-mole game. Each time you think you’ve got it, you realize that this might not be referring to what you thought it was! Once again, you find yourself trying to decipher how and what this is doing for you in your JavaScript program. In JavaScript, there are four key rules to memorize to determine what this refers to. There is also an order of precedence to these rules. In this tutorial, we’ll examine exactly what this does for you in JavaScript and memorize the four rules that determine its context. Let’s dig in now.


this refers to an object

One thing we can be confident of is that no matter what, this always is referring to an object. It will never refer to a primitive value like a boolean, string, or number. It will always be an object that it refers to.


Function Context

Before we get to the rules that determine how this works, we first need to understand a little bit about how functions in JavaScript work. Mainly, we need to be aware of the following:

Every function, while executing, has a reference to it’s current execution context. The current execution context is referred to as the this keyword.

In other words, this is what object is associated with the current function call

With this in mind, we must be mindful of the most critical thing to look for when dealing with this in JavaScript. We are referring to how the function is called and when it is called. In other words, we must pay special attention to the call site of that function. For it is the call site that determines what this is bound to. In essence, this acts as a type of dynamic scoping mechanism in JavaScript.

To demonstrate this, we will create several different JavaScript objects. Each object will have a property named prop1, and a property named decoder. The decoder property will have a reference to a function named thisdecoder() on all objects. We will see that the value contained in prop1 will depend entirely on the call site of the thisdecoder() function.

Here are the four this binding rules in order of precedence.

All rules depend on the call site of the function! If you are ever confused about what the binding of this is referring to, then you are to find the call site of the function and ask which of the following cases the function got executed as.


1. The new Binding

The rule that takes precedence over all others when dealing with this, is the JavaScript new keyword. We know that when the new keyword is used with a JavaScript function call, a new object gets created out of thin air. In this scenario, the newly created object is set to this for that function call.

function thisdecoder() {
    console.log(this.prop1)
};

function vehicle(make) {
    this.prop1 = make;
    this.decoder = thisdecoder;
};

//---Binding via new keyword---//
acar = new vehicle('Porche');
acar.decoder();
//  Porche

atruck = new vehicle('Mack');
atruck.decoder();
//  Mack

2. Explicit Binding

Explicit Binding is handled with the apply(), call(), and bind() methods of a function object. In JavaScript, functions are objects, therefore functions themselves can have methods. The first two methods are similar, in that the first argument provided to them is the object to which you want the this keyword to be bound to. apply() and call() are almost the same thing, but the difference between them is that call() accepts an argument list, while apply() accepts a single array of arguments. In our example, we only pass one argument, the object we want bound to this, so in our case apply() and call() work identically.

bind() is a little more confusing. It actually creates an entirely new function, which is then itself callable. When you call that new function, the this keyword is bound to the provided argument which was given to the bind() invocation.

function thisdecoder() {
    console.log(this.prop1)
};

var prop1 = 'This string lives in the global scope.';

var objectone = {
    prop1: 'This is a string in object ONE.',
    decoder: thisdecoder
};

var objecttwo = {
    prop1: 'This is a string in object TWO.',
    decoder: thisdecoder
};

var objectfour = {
    prop1: 'This is a string in object FOUR.',
    decoder: thisdecoder
}

var objectthree = {
    prop1: 'This is a string in object THREE.',
    decoder: thisdecoder
};

//---Explicit Binding---//
objectone.decoder.apply(objectthree);
//  This is a string in object THREE.

objecttwo.decoder.call(objectone);
//  This is a string in object ONE.

var bound = objectthree.decoder.bind(objecttwo);
bound();
//  This is a string in object TWO.

3. Implicit Binding

Implicit binding is pretty easy. Implicit binding happens when you call a function as a property or method of a given object. In our example below, all objects have a decoder property. Furthermore, each of these properties simply reference the same function called thisdecoder(). None of the given objects owns the thisdecoder() function any more than the other, they all simply have peer references to the same function. You could say we have put a reference to a function on an object. The implicit binding rules states that the object at the call site, also known as the base object, context object, or containing object, becomes the binding for the this keyword.

function thisdecoder() {
    console.log(this.prop1)
};

var prop1 = 'This string lives in the global scope.';

var objectone = {
    prop1: 'This is a string in object ONE.',
    decoder: thisdecoder
};

var objecttwo = {
    prop1: 'This is a string in object TWO.',
    decoder: thisdecoder
};

var objectfour = {
    prop1: 'This is a string in object FOUR.',
    decoder: thisdecoder
}

var objectthree = {
    prop1: 'This is a string in object THREE.',
    decoder: thisdecoder
};

//---Implicit Binding---//
objectfour.decoder();
//  This is a string in object FOUR.

objectthree.decoder();
//  This is a string in object THREE.

objecttwo.decoder();
//  This is a string in object TWO.

objectone.decoder();
//  This is a string in object ONE.

4. Default Binding Rule

Finally, we come to the default binding rule. The default binding rule applies when you call a function, and none of the prior three scenarios applies. It looks like a plain vanilla function call. When this is the case, this gets bound to the global object. In the browser, this is the Window object. note: You may be spontaneously roundhouse drop kicked by the the force of Douglas Crockford if you use this approach. We’re kidding of course. In all seriousness however, this binding rule has created many a security risk and headaches for JavaScript developers. To mitigate this, you can use strict mode in your JavaScript code, and the this binding will default to undefined rather than the global object.

function thisdecoder() {
    console.log(this.prop1)
};

var prop1 = 'This string lives in the global scope.';

var objectone = {
    prop1: 'This is a string in object ONE.',
    decoder: thisdecoder
};

var objecttwo = {
    prop1: 'This is a string in object TWO.',
    decoder: thisdecoder
};

var objectfour = {
    prop1: 'This is a string in object FOUR.',
    decoder: thisdecoder
}

var objectthree = {
    prop1: 'This is a string in object THREE.',
    decoder: thisdecoder
};

//---Default Binding---//
thisdecoder();
//  This string lives in the global scope.

What Does this Refer to in JavaScript Summary

In summary, it doesn’t matter where a function in JavaScript is declared. Nobody owns a function more than anybody else in JavaScript, everything is simply a reference. The only thing that matters with regard to the this binding in JavaScript is what the function call site looks like.

  • 1. new keyword binding

    new vehicle();
  • 2. Explicit binding with apply(), call(), or bind()

    objectone.decoder.apply(objectthree);
    objecttwo.decoder.call(objectone);
    
    var bound = objectthree.decoder.bind(objecttwo);
    bound();
  • 3. Implicit Binding

    objectfour.decoder();
    objectthree.decoder();
    objecttwo.decoder();
    objectone.decoder();
  • 4. The default binding rule

    thisdecoder();

These rules are a must for you to memorize in order to make your life easier when dealing with this bindings in JavaScript!

Click to share! ⬇️