What does ‘that = this’ in Javascript mean?

When you go through some of the popular JS libraries you might start noticing this peculiar line all over the place.

that = this
that.someFunction();

First impressions, you could figure out that it had something to do with the value of the variable this being inconsistent, so they had to store in a variable and use it later. So I did some digging into it and found out why this assignment was a necessity back then and how we can overcome them.

Let’s begin with a basic understanding of what a this variable actually is and then we’ll see how a this variable gets it’s value.

What is the this variable?

this is a special variable available inside the context of a function when it is invoked. The value of this in most cases, is determined by how a function is called. It can’t be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind/call method to set the value of a function’s this regardless of how it’s called, and ES2015 introduced arrow functions whose this is lexically scoped (i.e) it is set to the this value of the enclosing execution context. We’ll see more on how it works later.

There are four ways in which a this variable can get it’s value. The topic is extensive to be discussed in this post, but you can read about it here.

For the sake of sticking to the topic and for brevity, we’ll focus on only two ways.

First thing we have to understand is that, the value of this depends on the call site of the function, unless the value of this is explicitly set using call/bind functions. The call site of a function is the place where the function is actually invoked.

Type 1 – Standalone function invocation – Default Binding

Consider the following piece of code.

var name = "Global Name";
function myFunction() {
    console.log(this.name);
}

myFunction();

The above piece of code actually prints out “Global Name” rather than undefined as most of you would have expected. Let’s decode it.

Have a look at the call site:

myFunction()

As you can see, it is a standalone invocation of a function. Whenever a standalone invocation of a function is made, default binding applies and the this variable of the function is set to the global object. That’s why in this case, the global variable name got printed to the console.

Type 2 – Call with the dot operator

Consider the following piece of code

var obj = {
    name : 'Object Name',
    printName : function() {
        console.log(this.name);
    }
};

obj.printName(); //prints "Object Name"

Nothing fishy here, the code prints out ‘Object Name’. When we focus on the call site of the function,

obj.printName();

we can see that the function invocation is preceded by the dot operator, which in turn is preceded by an object reference. In other words, we can say that the function was invoked on that particular object reference. In such cases, the value of this is set to that particular object reference, in this case, it is the variable obj holding that reference.

Now to add a little twist, see what happens when you execute the following code.

var name = "Global Name";
var obj = {
    name : 'Object Name',
    printName : function() {
        console.log(this.name);
    }
};

var printNameReference = obj.printName;
printNameReference(); //prints "Global Name"

Whoa!! We got “Global Name” instead of “Object Name”. Again, we need to focus on the call site.

printNameReference()

Here you can see that the type of function invocation is a stand alone function invocation rather than a invocation using the dot operator. This means that the value of this was set to the global object.

The takeaway here is that, though the function was defined on the object, this does not necessarily mean that the value of this is always set to that particular object. It all depends on the way the function is invoked.

Now, that we have a basic understanding of how the this variable gets it value, we’ll take a step further.

Say we got a new requirement where we want to print the name after a couple of seconds. So we add a setTimeout to the printName function.

var name = "Global Name";
var obj = {
    name : 'Object Name',
    printName : function() {
        setTimeout(function() {
            console.log(this.name);
        }, 2000);
    }
};

obj.printName();    //prints "Global Name"

After a couple of seconds, you get “Global Name” printed out to the console. Wait! What??? We did call the function using the dot operator, didn’t we? Again we have to focus on the call site of the function that prints out the name to the console.

Note that in the above case, it is not the printName function that prints out the name to the console, but rather the anonymous function that is passed to setTimeout, that actually prints out the name.

A overly simplified implementation of setTimeout pretty much looks like this:

function setTimeout(fn, time) {
    //code to wait for time milliseconds
    fn();
}

Here, we can see that the function invocation is actually a stand alone invocation. This means that the anonymous function that we pass to the setTimeout function is actually invoked in this manner, causing the this variable of the anonymous function to be set to the global object.

Now, we get why “Global Name” was printed out to the console.

But we want to print the name associated with the particular Object. How do we fix this?

var name = "Global Name";
var obj = {
    name : 'Object Name',
    printName : function() {
        var that = this;
        setTimeout(function() {
            console.log(that.name);
        }, 2000);
    }
};

obj.printName();    //prints "Object Name"

This time “Object Name” got printed though we still haven’t changed the way the function is invoked. The anonymous function is still passed a parameter to setTimeout and inside it a standalone invocation of that function is done.

But the difference lies in the magic assignment

that = this

What this line actually does it that, it stores the value of this in a local variable named that, when the printName function is first invoked using the dot operator on the obj object.

In this case, the value of this would be the object obj since it was a dot operator invocation and it gets stored in the that variable.

Since the inner anonymous function is defined within the same scope, i.e, within the printName function, the anonymous function has access to all the variables defined inside the printName function throughout it’s life time.

Therefore, eventually when setTimeout invokes the anonymous function, it makes use of the that variable to get the value of the original this variable and prints out the correct name.

But unfortunately this does not work if you execute the following code:

var printNameReference = obj.printName;
printNameReference(); //prints "Global Name"

This is because the original invocation in this case, is a standalone invocation and this means the value assigned to the that variable would be the global object.. :/

The only way around it would be make use of call or bind functions, to explicity set the value of the this to the obj object as follows

printNameReference.call(obj);

or

printNameReference.bind(obj)();

This ensures that the value of this is set to obj object no matter what.

Note: Arrow functions cannot help us when the function is defined on the object literal as it will resolve to the enclosing lexical scope, which in this case is the global scope.

var name = "Global Name";
var obj = {
    name : 'Object Name',
    printName : function() {
        setTimeout(() => {
            console.log(this.name);
        }, 2000);
    }
};
obj.printName();    //prints "Object Name"
var printNameReference = obj.printName;
printNameReference(); //prints "Global Name"

You will see that “Global Name” will still be printed out. The reason is because arrow functions take the enclosing lexical scope, and the arrow function to setTimeout in the example is created each time the printName function is invoked. The printNameReference() invocation sets the scope of the printName function to global because of the way it is invoked and hence the arrow function to setTimeout will also take this scope.

Changing the printName function itself as arrow function does not help either.

var obj = {
    name : 'Object Name',
    printName : () => {
        setTimeout(() => {
            console.log(this.name);
        }, 2000);
    }
};

The above code will again set the printName function to the enclosing global scope, because that is where obj is declared.

I’ll try to add a future post that explains how and in which scenarios, arrow functions can help to preserve the value of the this variable.

I hope that the next time when you come across a that = this assignment when going through a library, you’ll be able to understand why it was actually done..See you in the next one guys…Peace.. đŸ™‚

Advertisements

10 thoughts on “What does ‘that = this’ in Javascript mean?

  1. Pingback: What does ‘that = this’ in JavaScript mean? – Full-Stack Feed

  2. This level of complexity is ridiculous. Of you’re going for the most fragile code. Definitely create anonymous functions and assign them all over the place in random spots so God knows what the scope is and how they’ll work and you’ll have to Google articles like this to figure out what’s going or just write clean code and follow language independent principles so you’re code makes sense.

    Like

  3. Pingback: Replacing ‘that = this’ assignments in Javascript with Arrow Functions | db writeups

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s