What's `this` keyword in JavaScript Functions and How it Works?

We can think about this as an implicit or hidden parameter that’s passed to all JavaScript functions. In OOP, object methods need access to the properties of the class. this keyword provides that binding and allow object methods to access its properties.

In JavaScript, the this keyword is used to refer to the current object within a method or the current execution context of a function.

Note: If you are familiar with other languages that use this like Java, please note that this behaves very differently in JavaScript.

Here’s an example:

const person = {
  name: 'Zayn',
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

person.greet(); // Output: "Hello, my name is Zayn"

In the example above, greet() is a method of the person which is an object. When we call greet() using the person.greet(), this inside the function will point to the person object.

The value of this may be different each time the function is called. The value of this depends on in which context it appears. It can be function, class, or global.

Let’s call the greet() function in the example above again but do it a little different this time:

const person = {
  name: 'Zayn',
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const greet = person.greet
greet(); // Output: "Hello, my name is undefined"

In the example above, we called the greet() function directly without invoking it on the person object. this will now be the global object (i.e., window in a browser), rather than the person object and hence it can’t find name property and prints undefined.

We can avoid this by explicitly binding this to the person object.

const person = {
  name: 'Zayn',
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const greet = person.greet.bind(person)
greet(); // Output: "Hello, my name is Zayn"

Here’s another example of how we can bind this to a function that’s not part of an object:

const person = {
  name: 'Zayn'
};

// This function doesn't belong to function object
function greet() {
  console.log(`Hello, my name is ${this.name}`);
}

greet(); // Output "Hello, my name is undefined"

// Bind greet() to the person object
const boundGreet = greet.bind(person); 
boundGreet(); // Output: "Hello, my name is Zayn"

When you run the function above, you’ll see the following output:

Hello, my name is undefined
Hello, my name is Zayn

This is because when we call greet() on the first line, this refers to the global object. Since it doesn’t have name property, it prints undefined as in “Hello, my name is undefined”. But when we explicitly bind greet() to the person using greet.bind(person), we get the correct output because this now refers to the person object and the name property can be accessed.

Can you guess what this points to in the following example:

function foo() {
  return console.log(this); // this points to global object
}

foo()

If you said global object (browser window), you guessed it right.

this and nested functions

Another thing to note is that this can be different inside nested functions. For example:

const person = {
  name: 'John',
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);

    setTimeout(function() {
      console.log(`Hello again, my name is still ${this.name}`);
    }, 1000);
  }
};

person.greet();

This prints:

Hello, my name is John
Hello again, my name is still undefined

Why is this.name undefined for the nested function that we call using setTimeout()? this here refers to the global object (window), rather than the person object. This is because the value of this is determined by how a function is called, and the nested function is not called as a method of the person object.

this and arrow functions

Arrow functions => do not have their own this value and they inherit the value from the parent scope. (and hence cannot be used as object methods.)

const person = {
  name: 'John',
  greet: function() {
    console.log(`Hello, my name is ${this.name}`);

    setTimeout(() => {
      console.log(`Hello again, my name is still ${this.name}`);
    }, 1000);
  }
};

person.greet(); 

This prints:

Hello, my name is John
Hello again, my name is still John

In the example above, we used an arrow function as the callback for setTimeout(). Since arrow functions do not have their own this value, this inside arrow functions is the same as the surrounding code. In this case, the value of thisrefers to the person object.

Speak Your Mind