Introduction
In JavaScript, almost everything is an object. An object can have methods - a function that is a property of the object.
const user = {
firstName: "Alicia",
lastName: "Keys",
greet: function () {
alert("Hello!");
}
};
user.greet();
In the above example, greet is a method as it is a function that is a property of the object user.
We often come across situations where an object method needs to access another property value within the object.
Let's see an example. Suppose in the printFullName method below, we want to print the user's full name and need to access firstName and lastName. In JavaScript, every function has access to a this
keyword and using this, we can access the required property values:
const user = {
firstName: "Alicia",
lastName: "Keys",
printFullName: function() {
console.log(this.firstName + " " + this.lastName);
}
};
user.printFullName()
//Output
//Alicia Keys
In this case, the value of this
refers to the object before the dot - "user".
In other object-oriented programming languages, the this
keyword always refers to the current instance of the class. However, in JavaScript, the this
keyword refers to different objects depending on how it is used:
- In an object method,
this
refers to the object. - Alone,
this
refers to the global object. - In a function,
this
refers to the global object. - In a function, in strict mode,
this
is undefined. - Methods like call(), apply(), and bind() can refer
this
to any object.
call(), apply(), and bind()
Suppose in addition to the user mentioned in the above example, we have another user whose full name we wish to retrieve. Shown below is one approach:
const user = {
firstName: "Alicia",
lastName: "Keys",
printFullName: function() {
console.log(this.firstName + " " + this.lastName);
}
};
const userTwo = {
firstName: "Jessica",
lastName: "Parker",
printFullName: function() {
console.log(this.firstName + " " + this.lastName);
}
};
user.printFullName(); //Alicia Keys
userTwo.printFullName(); //Jessica Parker
Obviously, this is not an efficient way of writing code because it's repetitive. Luckily, we have Function Borrowing. Function borrowing allows us to use the methods of one object on a different object without having to make a copy of that method and maintain it in two separate places. It is accomplished through the use of call(), apply(), or bind(), all of which exist to explicitly set this
on the method we are borrowing:
call()
const user= {
firstName: "Alicia",
lastName: "Keys",
printFullName: function() {
console.log(this.firstName + " " + this.lastName);
}
};
const userTwo= {
firstName: "Jessica",
lastName: "Parker",
};
user.printFullName.call(userTwo);
//Output
//Jessica Parker
What we tell the code to do here is to use the "printFullName" method of the "user" object on "userTwo".
Similarly, we can also declare the function outside the objects and call it as needed.
const printFullName = function () {
console.log(this.firstName + " " + this.lastName);
};
const user = {
firstName: "Alicia",
lastName: "Keys"
};
const userTwo = {
firstName: "Jessica",
lastName: "Parker"
};
printFullName.call(user); //Alicia Keys
printFullName.call(userTwo); //Jessica Parker
call() with arguments
call() can also accept arguments. In the code below, we pass the city "Paris" and country "France" as arguments to the call() method.
const printUserDetails = function (city, country) {
console.log(
this.firstName + " " + this.lastName + "," + city + "," + country
);
};
const user = {
firstName: "Alicia",
lastName: "Keys"
};
printUserDetails.call(user, "Paris", "France");
//Output
//Alicia Keys
apply()
While the call() method accepts arguments separately, the apply() method accepts arguments as an array. The above example can be rewritten as below using apply(). Notice that we are sending the arguments city and country in an array:
const printUserDetails = function (city, country) {
console.log(
this.firstName + " " + this.lastName + "," + city + "," + country
);
};
const user = {
firstName: "Alicia",
lastName: "Keys"
};
printUserDetails.apply(user, ["Paris", "France"]);
//Output
//Alicia Keys,Paris,France
bind()
While call() and apply() invoke the function immediately, bind() returns a copy of the function and sets this
to its first argument. The new function is then invoked at a later point in time.
const printUserDetails = function (city, country) {
console.log(
this.firstName + " " + this.lastName + "," + city + "," + country
);
};
const user = {
firstName: "Alicia",
lastName: "Keys"
};
const printLater = printUserDetails.bind(user, "Paris", "France");
//the new function printLater is invoked later
printLater();
//Output
//Alicia Keys,Paris,France
Conclusion
To wrap it up, we have learned that the this
keyword refers to different objects depending on how it is used. We make use of call(), apply(), or bind(), all of which exist to explicitly set this
independent of how a function is called.
The call() and apply() methods set the this
keyword and invoke the function immediately, whereas the bind() method creates a copy of the function and sets the this
keyword, which can be invoked later.
Do let me know your thoughts on this post and share it with your fellow devs if you found it helpful! :)