What is the “this” keyword in JavaScript?

About every Object Oriented Programming (OOP) language out there has a mechanism for referring to itself. Languages such as Python, Ruby, and Swift provide a self keyword for this purpose. On the other hand, languages such as C#, C++, Java and JavaScript uses the this keyword. This is often an object of confusion (pardon the puns!) and using it correctly can be challenging, but it is essential to becoming a proficient JavaScript programmer. In this blog post, we will explore what the “this” keyword is, why it is tricky, and how to use the “bind” method to change what “this” is referring to.

What is this?

In JavaScript, the “this” keyword refers to the object that the function is a method of. It is a variable that holds the value of the current execution context – the thing that is executing the current piece of code. The value of “this” depends on how the function is called.

Global: When “this” is used in the global context, it refers to the global object, which in a browser environment, is the window object. In Node.js, it is the global object. Try executing the following piece of code within a browser:

console.log(this === window); // Output: true

function sayHello() {
  console.log(this === window);
  console.log("Hello, World!");
}

sayHello(); // Output: true, "Hello, World!"

In the example above, we first check if “this” is equal to the “window” object using the strict equality operator (===). This will return true because we are running this code in a web browser environment.

Next, we define a function called “sayHello”. Inside the function, we check if “this” is equal to the “window” object, which will also return true. That is because the “sayHello” function is defined in the global scope and hangs off the window object.

Object: When “this” is used inside a method of an object, it refers to the object that the method belongs to.

const myObject = {
  name: "Tom",
  sayName() {
    console.log(this.name);
  }
};

myObject.sayName(); // Output: Tom

In the example above, we’re defining an object named myObject. Within it, we have a sayName method and within it, we are using the this keyword. In this usage, the this is referring to the object myObject.

Constructor: When “this” is used inside a constructor function, it refers to the newly created object that the constructor is creating.

function Person(name, age) {
  this.name = name;
  this.age = age;

  this.sayHello = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

const tom = new Person("Tom", 25);
tom.sayHello(); // Output: "Hello, my name is Tom and I am 25 years old."

In this example, we define a constructor function called “Person”. The function takes two parameters, “name” and “age”, which are used to set the properties “name” and “age” on the newly created object using “this”. We also define a method called “sayHello” on the object using “this”.

Next, we create a new object called “tom” using the “Person” constructor and passing in the values “Tom” and “25” for the “name” and “age” parameters, respectively. We then call the “sayHello” method on the “tom” object, which logs the string “Hello, my name is Tom and I am 25 years old.” to the console.

In this example, “this” refers to the object that the “Person” constructor is creating, which is the “tom” object in this case. When we call the “sayHello” method on the “tom” object, “this” refers to the “tom” object, which allows us to access the “name” and “age” properties on the object using “this.name” and “this.age”, respectively.

Explicit: When “this” is used with call() or apply(), it is explicitly defined and refers to the object that is passed as an argument to call() or apply(). Consider the following example:

const person = {
  name: "John",
  age: 30,
  sayHello: function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

const anotherPerson = {
  name: "Alice",
  age: 25
};

person.sayHello.call(anotherPerson); // Output: "Hello, my name is Alice and I am 25 years old."

In this example, we have an object called “person” with a “sayHello” method that logs a string to the console. We also have another object called “anotherPerson” with a “name” and “age” property.

When we call the “sayHello” method on the “person” object using the call() method and passing in the “anotherPerson” object as an argument, “this” inside the “sayHello” method refers to the “anotherPerson” object. This allows us to access the “name” and “age” properties of the “anotherPerson” object using “this.name” and “this.age”, respectively. The output of the code is “Hello, my name is Alice and I am 25 years old.”.

In this example, we’re explicitly defining the value of “this” using the “call()” method, which allows us to call the “sayHello” method on the “person” object with a different object as the context.

Here’s an example of “this” being used in the explicit context using the apply() method:

const person = {
  name: "John",
  age: 30,
  sayHello: function(greeting) {
    console.log(`${greeting}, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

const anotherPerson = {
  name: "Alice",
  age: 25
};

person.sayHello.apply(anotherPerson, ["Hi"]); // Output: "Hi, my name is Alice and I am 25 years old."

In this example, we have the same “person” and “anotherPerson” objects as before. However, the “sayHello” method now takes a “greeting” parameter that is used to customize the greeting that is logged to the console.

When we call the “sayHello” method on the “person” object using the “apply()” method and passing in the “anotherPerson” object as the first argument and an array containing the “greeting” parameter as the second argument, “this” inside the “sayHello” method refers to the “anotherPerson” object. This allows us to access the “name” and “age” properties of the “anotherPerson” object using “this.name” and “this.age”, respectively. The output of the code is “Hi, my name is Alice and I am 25 years old.”.

In this example, we’re explicitly defining the value of “this” using the “apply()” method, which allows us to call the “sayHello” method on the “person” object with a different object as the context and pass in an array of arguments.

Why is this tricky?

The “this” keyword can be tricky for several reasons. One of the main reasons is that its value can change depending on how a function is called. This can be confusing for developers who are not familiar with how “this” works in JavaScript.

For example, consider the following code:

const myObject = {
  name: "John",
  sayName() {
    console.log(this.name);
  }
};

myObject.sayName(); // Output: John

const sayName = myObject.sayName;
sayName(); // Output: undefined

In the first call to myObject.sayName(), “this” refers to the “myObject” object, and the output is “John”. However, in the second call to “sayName()”, “this” is not defined, and the output is “undefined”.

Another reason “this” can be tricky is that it is often used in asynchronous code, such as callbacks and event listeners. In these cases, “this” can change unexpectedly, leading to hard-to-debug errors. Consider this example:

const myObj = {
  firstName: "John",
  age: 30,
  sayHello: function() {
    console.log(`Hello, my name is ${this.firstName} and I am ${this.age} years old.`);

    setTimeout(function() {
      console.log(`One second later, my name is ${this.firstName} and I am ${this.age} years old.`);
    }, 1000);
  }
};

myObj.sayHello();

In this example, we have an object called myObj with a sayHello method that logs a greeting to the console. Inside the sayHello method, we also have a setTimeout() function that logs a message to the console after one second. When you run this example, you get the following output:

"Hello, my name is John and I am 30 years old."
"One second later, my name is undefined and I am undefined years old."

This is because this inside the setTimeout() function refers to the global object (i.e., window), rather than the myObj object.

Bind to the Rescue

To fix this, we can use the bind() method to bind the value of this to the myObj object inside the setTimeout() function:

const myObj = {
  name: "John",
  age: 30,
  sayHello: function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);

    setTimeout(function() {
      console.log(`One second later, my name is ${this.name} and I am ${this.age} years old.`);
    }.bind(this), 1000);
  }
};

myObj.sayHello();

In this modified example, we use the bind() method to bind the value of this to the myObj object inside the setTimeout() function. Now, when we run the code, we’ll see the expected output in the console without any errors.

You’ll run into the “bind()” keyword in a lot of Angular and React codebases. The “bind()” method returns a new function with “this” set to the value of the first argument passed to it.

You can learn more about bind from MDN, here.

ES6 Fat Arrow Syntax

I want to note that there is an alternative to using the “bind()” method. You can instead use the => syntax that you get with ES6. Here’s the modified example:

const myObj = {
  name: "John",
  age: 30,
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);

    setTimeout(() => {
      console.log(`One second later, my name is ${this.name} and I am ${this.age} years old.`);
    }, 1000);
  }
};

myObj.sayHello();

Closing Remarks

Understanding the “this” keyword in JavaScript can help you a lot in your JavaScript development journey. The value of “this” can change depending on how a function is called, which can be confusing. To avoid this confusion, developers can use the “bind” method (or the ES6 fat arrow syntax) to set “this” explicitly.

Leave a Comment

Your email address will not be published. Required fields are marked *