call vs apply
call and apply invoke a function with an explicitly specified this context, and they differ only in how the arguments are passed: call takes them comma separated, apply takes them as a single array. The return value, the moment of the call and the behaviour of this are identical in both.
Theory
TL;DR
- Both methods invoke the function immediately and return its result.
- The first argument of both is
thisArg, the call context. call-> arguments comma separated:func.call(thisArg, arg1, arg2, arg3).apply-> arguments as an array:func.apply(thisArg, [arg1, arg2, arg3]).- Arguments known up front ->
call; arguments already in an array ->apply. - In modern JavaScript both are often replaced by the spread operator:
func(...args).
Quick example
| Method | How arguments are passed | Call example |
|---|---|---|
call | listed comma separated | func.call(thisArg, arg1, arg2, arg3) |
apply | passed as an array | func.apply(thisArg, [arg1, arg2, arg3]) |
function greet(city, job) {
console.log(`I am ${this.name} from ${city}, working as a ${job}`);
}
const user = { name: 'Maria' };
// call: arguments comma separated
greet.call(user, 'Kyiv', 'Frontend developer');
// apply: arguments as an array
greet.apply(user, ['Kyiv', 'Frontend developer']);Both calls print the same thing:
I am Maria from Kyiv, working as a Frontend developer
When to use which
| Scenario | Better choice |
|---|---|
| The arguments are known in advance | call |
| The arguments are already in an array | apply |
An example with an array of arguments:
function sum(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
// without apply you would have to unpack the array by hand
console.log(sum.call(null, nums[0], nums[1], nums[2]));
// with apply you simply pass the array
console.log(sum.apply(null, nums)); // 6The longer the array, the clearer the advantage of apply: unpacking ten elements by hand through call is impossible when the length is not known in advance.
The modern spread equivalent
In modern versions of JavaScript (ES6+) apply is often replaced by the spread operator:
const nums = [1, 2, 3];
console.log(sum(...nums)); // the same result as sum.apply(null, nums)Spread reads more simply and does not require an artificial null context. apply is still appropriate when this really has to be substituted, for example fn.apply(ctx, args), or in legacy code without ES6 support.
Summary table
| Property | call | apply |
|---|---|---|
Context (this) | Explicitly given as the first argument | The same |
| Argument passing | Comma separated | As an array |
| Returns | The function result | The function result |
| Invokes immediately | Yes | Yes |
| Modern alternative | Spread: func(...args) | Spread: func(...args) |
Common mistakes
- Passing an array into
call.sum.call(null, [1, 2, 3])hands the array over as the first parametera, so the result is"1,2,3undefinedundefined"instead of6. - Listing arguments in
apply.sum.apply(null, 1, 2, 3)ignores everything after the second parameter:applyreads only one array. - Confusing them with
bind.callandapplyinvoke the function right away, whilebindonly returns a new function that has to be called separately. - Forgetting about
thisArg. The first argument is mandatory by position: when no context is needed you passnullrather than skipping it. - Expecting different performance. There is essentially no difference; choosing between
callandapplyis a matter of convenience, not speed.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.