call() and apply() in JavaScript
By Flavio Copes
Learn how to use call() and apply() in JavaScript to invoke a function with a chosen this value, where call() takes a list and apply() takes an array.
call() and apply() are two functions that JavaScript offers to perform a very specific task: call a function and set its this value.
Check out my “this” guide to know all the details about this particular variable
Inside a regular function, this is decided by how the function is called, not by where you defined it. Call it as a method of an object, and this is that object. Call it standalone, and this is undefined (in strict mode).
You can’t change that from the outside, except by using call() or apply(). With those methods, you pass an object as the first argument, and that object will be used as this inside the function.
When is this useful?
Say you have a function that’s not attached to any object, but its body uses this. You can run it on any object that has the properties it expects:
const car = {
brand: 'Ford',
model: 'Fiesta'
}
const drive = function(from, to, kms) {
console.log(`Driving for ${kms} kilometers from ${from} to ${to} with my car, a ${this.brand} ${this.model}`)
}
drive.call(car, 'Milan', 'Rome', 568)
drive.apply(car, ['Milan', 'Rome', 568])
Both calls print the same thing:
Driving for 568 kilometers from Milan to Rome with my car, a Ford Fiesta
What’s the difference between call() and apply()?
They perform the same thing, but have a difference. In call() you pass the function parameters as a comma separated list, taking as many parameters as you need. In apply() you pass a single array that contains the parameters.
A common trick to remember which is which: apply takes an array.
Since the spread operator was introduced, apply() is needed much less often. If your arguments are stored in an array, you can spread them into call():
const trip = ['Milan', 'Rome', 568]
drive.call(car, ...trip)
What if you want to call the function later?
call() and apply() invoke the function immediately. If instead you want a new function with this permanently set, to call whenever you want, use bind():
const driveMyCar = drive.bind(car)
driveMyCar('Milan', 'Rome', 568)
Watch out for arrow functions
Arrow functions don’t have their own this. They inherit it from the surrounding scope, and neither call() nor apply() can change that:
const fly = (from, to) => {
console.log(`Flying from ${from} to ${to} with my ${this.brand}`)
}
fly.call(car, 'Milan', 'Rome')
//this.brand is undefined
The car argument is silently ignored. If you need call() or apply() to set this, define the function with the function keyword.
Related posts about js: