JavaScript: this is easy and what do you need to know about it!

Subscribe to my newsletter and never miss my upcoming articles

Introduction

Let me start this article by thanking the readers of my series, JavaScript: Cracking the Nuts for liking and loving it so far. In this article, we will go through another fundamental but equally misunderstood aspect of JavaScript called, the this keyword.

It is not mandatory but if you are new to the series, I would recommend you to go through the previous articles for other fundamental concepts like,

Alright, so let us get started. At the end of the article, you should have better understanding with,

  • What is this in JavaScript.
  • How to make this sounds less confusing than ever.
  • Rules of this and the usage.
  • Importantly, this is easy!

Lengthy Read Alert ⚠️

Unlike other articles from the series, this one is going to be bit lengthy. After going over several tutorials, I felt that, one should connect various aspects together to understand the concept of this well. For example, the concept of call => apply => bind is very related to understanding this keyword. They got to be discussed together.

I could have broken things into multiple articles but, it is better to be together as the concepts are very inter-related. Hence the lengthy read alert!

Take your favorite beverages, relax and start reading. I am sure, you are going to enjoy it.

What is this?

this is a keyword in JavaScript and the existence of it is to allow us in,

  • Reusing functions in different contexts.
  • Identifying which object to focus on when a method is invoked.

Remember that, when an Execution Context is created in JavaScript, it creates a special entity called, this.

  • In Global execution context, this is equal to the global object Window.
  • In Function execution context, this is equal to the Window object by default but, the behavior changes based on the phenomenon called, binding. Do not confuse it with the bind() method in JavaScript. The bind() method is just yet another way of binding stuff. There is more to it. We will see that in a while and 90% of the usage of this are around it.

Rules of this

It can be little challenging to understand a function's this keyword as it behaves a differently in JavaScript compared to other languages. When it comes to this, the important question to ask is,

Where is the function invoked? We do not know what is there in the this keyword until the function is invoked.

The usage of this can be categorized into four different binding aspects.

Implicit binding

Implicit binding covers most of the use-cases we deal with the this keyword. In implicit binding, left of the dot(.) operator adjacent to a function at invocation time determines what this is binding to.

Here is an example,

Example:

var user = {
    name: 'GreenRoots',
    address: 'HashNode',
    getName: function() {
        console.log(this.name);
    }
};

user.getName();

Explanation: In the above example, this bound to the user object as the left of the dot(.) operator adjacent to the function logName() is user object. Hence this.name is going to log, GreenRoots in the console.

Let's take another example to explain this concept better way,

Example:

 function decorateLogName(obj) {
      obj.logName = function() {
          console.log(this.name);
      }
  };

  var tom = {
      name: 'Tom',
      age: 7
  };

  var jerry = {
      name: 'jerry',
      age: 3
  };

  decorateLogName(tom);
  decorateLogName(jerry);

  tom.logName();
  jerry.logName();

Explanation: In the above example, we have two objects, tom and jerry. We have decorated(enhanced) these objects by attaching a method called, logName().

Just notice when we invoke tom.logName(), the left of the dot(.) operator adjacent to the function logName() is the tom object. Hence this bound to the tom object and it logs the value tom(this.name is equal to tom here). Same applies when jerry.logName() is invoked.

Clear enough? Great! Now, let us take one example with JavaScript class which is nothing but a function but, we will be able to create different instances of it,

Example:

var Cartoon = function (name, age, friend) {
      return {
          name: name,
          age: age,
          logName: function() {
              console.log(this.name);
          },
          friend: {
              name: friend,
              logName: function() {
                  console.log(this.name);
              }
          }
      }
  };

  var tom = Cartoon('Tom', 7, 'Jerry');
  tom.logName(); // Should print 'Tom'
  tom.friend.logName(); // Should print 'Jerry'

Explanation: Here we have a class called, Cartoon. Cartoon has a method called, logName(). It also has a property called, friend which is an object. To make things bit tricky, the object friend has a method called, logName() as well.

When the Cartoon class is instantiated, we get an instance called, tom by passing the name, i.e, Tom, age as 7 and the friend's name as Jerry.

When tom.logName() invokes, the left of the dot(.) operator adjacent to the function logName() is tom and this bound to it. So this.name here points to tom's name which we have passed as Tom before.

When tom.friend.logName() invokes, the left of the dot(.) operator adjacent to the function logName() is, friend. So this points to the object friend and the this.name is friend's name, i.e, Jerry.

Hope we understood the rule and logic of implicit binding fully to apply and realize it. Let's move on.

Explicit binding

We are aware that, JavaScript creates an environment to execute the code we write. This environment includes stuffs beyond the actual code we write.

It takes care of the memory creation for variables, functions, objects etc in the creation phase. Finally executes the code in execution phase. This special environment is called, JavaScript Execution Context. You can read more about it from here.

There are many such environments(Execution Contexts) in a JavaScript application. Each Execution Context operates independently from each other. But at times, we may want to use stuff from one execution context to another. That is where explicit binding comes in play. We can bind stuff from one context into the context of a different environment for execution using this.

In Explicit binding, we can call a function with an object when the function is outside of the execution context of the object.

There are three very special methods, call(), apply() and bind() help in achieving explicit binding.

call() method

With call() method, the context with which the function has to be called will be passed as a parameter to the call(). Let us see with an example,

Example:

var getName = function() {
     console.log(this.name);
 }
 var user = {
   name: 'GreenRoots',
   address: 'HashNode'  
 };

 getName.call(user);

Explanation: What we see here is, the call() method is invoked on a function called, getName(). The getName() function just logs this.name. But what is this here? That gets determined by, what has been passed to the call() method.

Here this will bind to the user object because, we have passed user as parameter to the call() method. Hence this.name should log the value of name property of user object, i.e, GreenRoots.

In the above example, we have passed just one argument to call(). But, we can pass multiple arguments to call(), if required. Let's take another example to understand that,

Example

var getName = function(hobby1, hobby2) {
     console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2);
 }
 var user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

 var hobbies = ['Swimming', 'Blogging'];
 getName.call(user, hobbies[0], hobbies[1]);

Explanation: Notice that, we have passed two more arguments here in the call() method. The first argument must be the object context with which the function has to be invoked. Other parameters could be just values to use. Here I am passing Swimming and Blogging as two parameters to the getName() function.

Do you notice a pain point here? In case of call(), the arguments need to be passed one by one which is not so smart way of doing thing! That's where our next method apply() comes into picture.

apply() method

The hectic way of passing the arguments to call() method can be solved by another alternate method called, apply(). It is exactly same as call() but, allows to pass the arguments more convenient way. Have a look,

Example

var getName = function(hobby1, hobby2) {
     console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2);
 }
 var user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

 var hobbies = ['Swimming', 'Blogging'];
 getName.apply(user, hobbies);

Explanation: As you see here, we are able to pass an array as arguments which is much more convenient than passing one by one.

When you have only one value argument or no value arguments to pass, use call(). When you have multiple value arguments to pass, use apply().

bind() method

call() invokes the function by passing the context of this. bind() is similar to the call() but, instead of calling the function directly, bind() returns a brand new function and we can invoke that instead.

Example:

var getName = function(hobby1, hobby2) {
     console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2);
 }
 var user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

 var hobbies = ['Swimming', 'Blogging'];
 var newFn = getName.bind(user, hobbies[0], hobbies[1]); 

 newFn();

Explanation: As we see above, the getName.bind() doesn't invoke the function getName(). It returns a new function, newFn and we can invoke is as, newFn().

new binding

A Constructor function is created with the new keyword. Here is an example of a Constructor function,

var Cartoon = function(name, animal) {
     this.name = name;
     this.animal = animal;
     this.log = function() {
         console.log(this.name +  ' is a ' + this.animal);
     }
 };

We can create the objects using the new keyword as,

 var tom = new Cartoon('Tom', 'Cat');
 var jerry = new Cartoon('Jerry', 'Mouse');

The constructor function's new binding rule states that, when a function is invoked with the new keyword, the this keyword inside the function bind to the new object being constructed.

Sounds complex? Ok, let's break it down. Take this line,

var tom = new Cartoon('Tom', 'Cat');

Here the function Cartoon is invoked with the new keyword. Hence this will be bound to the new object being created here, which is tom .

Global Object binding

What will be the output of this code execution? What is this bind to here?

var sayName = function(name) {
    // 'use strict';
    console.log(this.name);
};

window.name = 'Tapas';
sayName();

if the this keyword is not resolved with any of the above bindings, implicit, explicit or new then, the this is bind to the window(global) object.

Arrow functions, no binding?

ES6 introduced arrow functions which don't provide their own this binding. As we have seen so far, in regular functions the this keyword represented the object that called the function, which could be the window, the document, user-defined or whatever.

With arrow functions the this keyword always represents the object that defined the arrow function.

Arrow functions use lexical scoping and ‘this’ refers to it’s current surrounding scope. arrow functions don't bind their own scope, but inherit it from the parent.

Example time. Let us see it working.

var testHobbies = {
  hobbies: ['Cricket', 'Football', 'Blogging'],
  name: 'Alex',
  logHobbies() {
     this.hobbies.forEach((elem) => {
     console.log(`${this.name} knows ${elem}`);
  });
  }
}

Here the logHobbies() method iterate through the hobbies and log them in console. Notice, we are using an arrow function in forEach. The this inside the arrow function would bind to the object testHobbies as there is no this binding for the arrow functions and it always bind to the parent one.

Hence invoking testHobbies.logHobbies() would perfectly log as,

Alex knows Cricket
Alex knows Football
Alex knows Blogging

Now let us just bring a twist to it. Notice the modification I have made below. Instead of an arrow function, the for-each uses a regular function.

var testHobbies = {
  hobbies: ['Cricket', 'Football', 'Blogging'],
  name: 'Alex',
  logHobbies() {
    this.hobbies.forEach(function(elem){
    console.log(`${this.name} knows ${elem}`);
  });
  }
}

What do you think, this would be bound to here inside forEach? It is not an arrow function. It is a regular function and it has it's own execution context. In that execution context, there is nothing called, name. Hence this.name is undefined.

Hence the output will be,

undefined knows Cricket
undefined knows Football
undefined knows Blogging

We will see it in more details in the future articles on Scope and Closure.

Use Strict and this

Normally, in global scope this keyword refers to Window object,

<script>
console.log(this);  //returns Window object.
</script>

In JavaScript strict mode also, this keyword in global scope returns Window object. However it behaves differently in function scope.

See the following example,

<script>
        "use strict;"
        console.log(this);

        function testThis() {
            "use strict";
            console.log('testThis', this);
        }

        testThis();
    </script>

It will log the following output in console,

Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
testThis undefined

Conclusion

Yes, Understanding this is easy! But at the same time, it could be challenging to comprehend the rules and usage of this. We will understand this better when we focus on the question, Where is the function invoked?

In most of the cases, the usage would be with Implicit Binding. There will be usage with explicit binding with call(), apply() and bind(). With many of the JavaScript based frameworks like Reactjs, Angular etc we see the usage of arrow functions as well.

Just note, as long as you have these rules understood and practiced, I am sure, you will agree that, this is really easy to work with!

Credits and Resources


If it was useful to you, please Like/Share so that, it reaches others as well. To get e-mail notification on my latest posts, please subscribe to my blog by hitting the Subscribe button at the top of the page.

In the future posts of the series, I'll be explaining about other fundamental concepts called, Scope and Closure. Stay Tuned.

Comments (2)

John Philip's photo

Good explanation

Tapas Adhikary's photo

☝ UI/UX Enthusiast | 💻 Work @MicroFocus | ✍️ Blogger | 👨‍🏫 Mentor | 🎤 Speaker | 🍟 Foodie

Thanks John Philip!