What is the difference between using call
and apply
to invoke a function?
var func = function() {
alert(\'hello!\');
};
Another example with Call, Apply and Bind. The difference between Call and Apply is evident, but Bind works like this:
}
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(a,b) {
return this.name + " " + a + " " + b;
}
var reader = new Person('John Smith');
reader.getName = function() {
// Apply and Call executes the function and returns value
// Also notice the different ways of extracting 'getName' prototype
var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
console.log("Apply: " + baseName);
var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy");
console.log("Call: " + baseName);
// Bind returns function which can be invoked
var baseName = Person.prototype.getName.bind(this, "is a", "boy");
console.log("Bind: " + baseName());
}
reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/
The difference is that apply
lets you invoke the function with arguments
as an array; call
requires the parameters be listed explicitly. A useful mnemonic is "A for array and C for comma."
See MDN's documentation on apply and call.
Pseudo syntax:
theFunction.apply(valueForThis, arrayOfArgs)
theFunction.call(valueForThis, arg1, arg2, ...)
There is also, as of ES6, the possibility to spread the array for use with the call
function, you can see the compatibilities here.
Sample code:
function theFunction(name, profession) {
console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
Both call()
and apply()
are methods which are located on Function.prototype
. Therefore they are available on every function object via the prototype chain. Both call()
and apply()
can execute a function with a specified value of the this
.
The main difference between call()
and apply()
is the way you have to pass in arguments into it. In both call()
and apply()
you pass as a first argument the object you want to be the value as this
. The other arguments differ in the following way:
call()
you have to put in the arguments normally (starting from the second argument)apply()
you have to pass in array of arguments.let obj = {
val1: 5,
val2: 10
}
const summation = function (val3, val4) {
return this.val1 + this.val2 + val3 + val4;
}
console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array
console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually
The this
value can be tricky sometimes in javascript. The value of this
determined when a function is executed not when a function is defined. If our function is dependend on a right this
binding we can use call()
and apply()
to enforce this behaviour. For example:
var name = 'unwantedGlobalName';
const obj = {
name: 'Willem',
sayName () { console.log(this.name);}
}
let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable
copiedMethod();
// this is now window, unwantedGlobalName gets logged
copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
To answer the part about when to use each function, use apply
if you don't know the number of arguments you will be passing, or if they are already in an array or array-like object (like the arguments
object to forward your own arguments. Use call
otherwise, since there's no need to wrap the arguments in an array.
f.call(thisObject, a, b, c); // Fixed number of arguments
f.apply(thisObject, arguments); // Forward this function's arguments
var args = [];
while (...) {
args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments
When I'm not passing any arguments (like your example), I prefer call
since I'm calling the function. apply
would imply you are applying the function to the (non-existent) arguments.
There shouldn't be any performance differences, except maybe if you use apply
and wrap the arguments in an array (e.g. f.apply(thisObject, [a, b, c])
instead of f.call(thisObject, a, b, c)
). I haven't tested it, so there could be differences, but it would be very browser specific. It's likely that call
is faster if you don't already have the arguments in an array and apply
is faster if you do.
Let me add a little detail to this.
these two calls are almost equivalent:
func.call(context, ...args); // pass an array as list with spread operator
func.apply(context, args); // is same as using apply
There’s only a minor difference:
- The
spread
operator ... allows passing iterableargs
as the list to call.- The
apply
accepts only array-like args.
So, these calls complement each other. Where we expect an iterable, call
works, where we expect an array-like, apply
works.
And for objects that are both iterable and array-like, like a real array, we technically could use any of them, but apply will probably be faster because most JavaScript engines internally optimize it better.
I'd like to show an example, where the 'valueForThis' argument is used:
Array.prototype.push = function(element) {
/*
Native code*, that uses 'this'
this.put(element);
*/
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9]
**details: http://es5.github.io/#x15.4.4.7*