Before we jump in to what call()
, apply()
or bind()
it’s important to understand what this
is in JavaScript. Every function in Javascript while executing has a reference to the its current execution context, which is called “this”. (Ok, not every function, ES6 arrow functions are the exception).
this
determined?Kyle Simpson, in his Deep Javascript Foundations course on Frontend Masters, repeats this phrase over and over:
The only thing that matters is how the function was called
Now, this (no, not this
) is where call()
, apply()
and bind()
come in. When you use any of these methods, you are explicitly telling JavaScript what this
should refer to when the function is called. If you are calling the function with any of those three methods, then you are explicitly telling JavaScript what this
should refer to.
The other two ways that this
is determined is either by the implicit binding rule, or the default rule (the global object is set to this
). Implicit binding looks like this:
function sayMyName() {
console.log(`Hi, ${this.name}!`)
}
var beyonce = { name: 'Beyonce', sayMyName }
beyonce.sayMyName() // Hi, Beyonce!
In this code, this
refers to the object beyonce
. JavaScript implicitly used
the object from where the function it was called as this
.
Now, let’s look at how to explicitly tell JavaScript what this
refers to:
When you use call()
or apply()
, the function is invoked immediately, but if you use bind()
then you’re setting what this
points to when the function is eventually invoked.
Here’s my summary of what each of them do:
call()
Plain english: with this function, run it immediately and use the first parameter I give you as the object that this
should refer to within that function. The following parameters that I give you (comma separated) should be used for the remaining parameters needed for the function.
Example code:
var cat = { name: 'Gigi', hunger: 10 }
function feedTheCat(foodType, amount) {
this.hunger -= amount
console.log(
`${this.name} is well fed with some ${foodType} food.
Hunger level is now ${this.hunger}`
)
}
feedTheCat.call(cat, 'wet', 5)
// Output:
// Gigi is well fed with some wet food. Hunger level is now 5
The above code in plain english: I have a cat
whose name
is Gigi and hunger level is 10
(line 1). Here’s a function that feeds the cat. The function first reduces the hunger level of the cat by the amount passed in to the function. Then console.log
the cat’s name, the type of food and the new hunger level.
Lastly, for the function feedTheCat
invoke the function with cat
set as the this
parameter, use wet
as the foodType
and the amount
as 5
.
apply()
Plain english: with this function, run it immediately and use the first parameter I give you as the object that this
should refer to within that function. The following parameters that I give you (in an array) should be used for the remaining parameters needed for the function.
Example:
var cat = { name: 'Gigi', hunger: 10 }
function feedTheCat(foodType, amount) {
this.hunger -= amount
console.log(
`${this.name} is well fed with some ${foodType} food. Hunger level is now ${
this.hunger
}`
)
}
feedTheCat.apply(cat, ['wet', 5])
// Output: Gigi is well fed with some wet food. Hunger level is now 5
The above code in plain english: same as call()
except this time, use the values within the array for the function parameters, rather than a comma-separated list.
bind()
Plain english: For this function, set the value of this
to the first parameter that I give you, but don’t execute it yet!
Example:
var cat = { name: 'Gigi', hunger: 10 }
function feedTheCat(foodType, amount) {
this.hunger -= amount
console.log(
`${this.name} is well fed with some ${foodType} food. Hunger level is now ${
this.hunger
}`
)
}
feedTheCat.bind(cat)('wet', 5)
// Output: Gigi is well fed with some wet food. Hunger level is now 5
The above code in plain english: first bind this
to cat
for the function feedTheCat
. Now, call the function with the following parameters ”wet”, 5
.
You could also pass in the function parameters comma-separated, like this:
feedTheCat.bind(cat, 'wet', 5)()
Typically, when you use bind
you would create a new bounded function and then call the function later, something like this:
var gigi = { name: 'Gigi', hunger: 10 }
var oliver = { name: 'Oliver', hunger: 5 }
var feedTheCatGigi = feedTheCat.bind(gigi)
var feedTheCatOliver = feedTheCat.bind(oliver)
feedTheCatGigi('wet', 5)
feedTheCatOliver('dry', 5)
That way you can change the value of this
for different objects.
call()
and apply()
are very similar, except that apply()
accepts the arguments for the function as an array.
So if I were to rename apply()
to be much more descriptive of what it actually does, I would rename it to callUsingArrayOfValues()
, but that’s a mouthfuls, so we’ll stick with apply()
.
I think I get tripped up on it because bind()
doesn’t invoke the function, so I would assume that a similar word like apply()
wouldn’t invoke it either. Just remember that bind()
doesn’t invoke the function, but the other two do.
call()
explicitly binds this
, function parameters are passed in comma-separated. Function is immediately invoked.apply()
same as call()
except function parameters are passed in as an arraybind()
explicitly binds this
for the function, but the function is NOT immediately invoked.