Call Bind and Apply in Javascript


Pre Requisites
this
keyword
Before we dive into how to use call
, apply
, and bind
in JavaScript, let's first understand what the this
keyword means. Just like Albert Einstein said, 'Everything is relative,' the meaning or value of the this
keyword also changes.
But simplifying the concept, we could say, this
refers to the object that is currently executing the function and provides context within the function's scope.
Lets understand the different 'faces' of this
keyword with examples.
console.log(this)
// window object
when we execute this, the context for console log is window object.
const obj = {
name: 'Portgas D Ace',
thisValue: this
}
console.log(obj.thisValue)
// window object
Again, the context in which obj
was created, is window object, hence the output.
Now lets try something different with object above.
const obj = {
name: 'Portgas D Ace',
thisValue: function () {
let name = 'Monkey D Luffy'
console.log(this.name)
}
}
obj.thisValue()
// Portgas D Ace
Weird huh? Not at all!
The context in which the function inside thisValue
was created is object itself. So the value of this
inside the function is obj, therefore this.name
is equivalent to obj.name
.
Let's raise the bar for the above question, think thoroughly and answer the next one.
const obj = {
name: 'Portgas D Ace',
thisValue: () => {
let name = 'Monkey D Luffy'
console.log(this.name)
}
}
obj.thisValue()
Wait! isn't it the same as before?
except its not.
This time output will be undefined
, because the arrow functions do not have their own this
keyword, they will use the this
keyword of whatever was outside the function when it was created.
Outside, the value of this
was window
object as explained in previous example, hence the answer.
Now lets see a different example for this
keyword and find move on to learn call apply and bind.
function awesome() {
console.log(`${this.name} is Awesome!`);
}
const onePiece = {
name: "Aokiji",
awesome: awesome,
announce: function() {
console.log(`Hey, I am ${this.name}`);
}
};
let newAwesome = onePiece.awesome;
newAwesome();
// undefined is Awesome!
We have created newAwesome
in the global context, so whatever onePiece.awesome
is, the value for its this
must be a window object. So when we tried to get name from this, we got undefined
.
One last example, and then we will learn the Call, Bind and Apply methods. Here we go!
const onePiece = {
country: 'Skypiea',
timeout: function () {
setTimeout(() => {
console.log(this)
}, 100)
},
timeout2: function () {
setTimeout(function() {
console.log(this)
}, 100)
}
}
onePiece.timeout() // onePiece
onePiece.timeout2() // window
- First console log will be obj2 because as we learned before, the arrow functions do not have their own this keyword, so the
this
inside arrow function will be of its parent's context, i.e. onePiece - Second console log is window object because callbacks are executed in whole different context, which is Global (window).
Call, Apply and Bind
Call
const onePiece = {
mc: 'Monkey D Luffy',
sideKick: 'Zoro and Sanji',
message: function() {
return `${this.sideKick} will help ${this.mc} to grow stronger`
}
}
const Naruto = {
mc: 'Naruto Uzumaki',
sideKick: 'Sasuke',
message: function() {
return `${this.sideKick} will help ${this.mc} to grow stronger`
}
}
As we can see, the above objects has one thing common, i.e. message function. Only if we had a way to borrow the function from onePiece object.
Well, we have and its called call
.
const onePiece = {
mc: 'Monkey D luffy',
sideKick: 'Zoro and Sanji',
message: function(goal) {
return `${this.sideKick} will help ${this.mc} to grow stronger and get ${goal}`
}
}
const Naruto = {
mc: 'Naruto Uzumaki',
sideKick: 'Sasuke',
}
const NarutoMessage = onePiece.message.call(Naruto, 'position of Hokage')
console.log(NarutoMessage) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage`
This concept is called function borrowing.
Here, call method's first argument will override the this
of function.
Not only this, all other arguments will act as parameter of the function we borrowed.
Apply
Its just same as call
but instead of sending the extra arguments like before, it will take an array of arguments like this.
const NarutoMessage = onePiece.message.call(Naruto, ['position of Hokage'])
console.log(NarutoMessage) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage
Bind
Bind does the same but it returns the copy of that function bound with this
of our choice.
Example:
const NarutoMessage = onePiece.message.bind(Naruto, 'position of Hokage')
console.log(NarutoMessage()) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage
Applications of Call Apply and Bind IRL
Since arrays don't have max method, you could use
Math.max
that is used for two numbers like this :arr = [3, 6, 77, 69, 22, 0] // No need to assign/override **this**, so null. console.log(Math.max.apply(null, arr)) //77
You can use the concept of bind and apply to create a function that curries a given function.
You can use bind to bind an event listener to an element :
const button = document.getElementById("myButton"); const handleClick = function(event) { console.log("Button clicked!", this); // 'this' is the button element }; button.addEventListener("click", handleClick.bind(button));