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 thatthis
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 this
refers to the person
object.