What is the difference between JavaScript’s Function.prototype.call() and Function.prototype.apply() methods?
When working with JavaScript functions, developers often encounter both call() and apply() methods for invoking functions with a specified this value and arguments. What are the key differences between these two methods, and when should you use one over the other?
For example, consider this function:
const func = function() {
alert("Hello world!");
};
How would func.apply() and func.call() differ in their execution?
Specifically, I’d like to understand:
- How do call() and apply() differ in how they handle function arguments?
- Are there any performance considerations between the two methods?
- In what scenarios is it more appropriate to use call() versus apply()?
- Can you provide practical examples demonstrating the use cases for each method?
The fundamental difference between JavaScript’s Function.prototype.call() and Function.prototype.apply() lies in how they handle function arguments. call() accepts arguments individually as separate parameters, while apply() accepts arguments as an array or array-like object. Both methods allow you to invoke a function with a specified this value, but their syntax and use cases differ significantly, with call() being slightly more performant due to the absence of array-argument handling overhead.
Contents
- Argument Handling Differences
- Performance Considerations
- Use Cases and Scenarios
- Practical Examples
- Modern Alternatives
Argument Handling Differences
The core distinction between call() and apply() is how they pass arguments to the invoked function. As explained in multiple sources, call() takes arguments individually, while apply() takes arguments as an array.
call() Method Syntax
function.call(thisArg, arg1, arg2, arg3, ..., argN)
apply() Method Syntax
function.apply(thisArg, [arg1, arg2, arg3, ..., argN])
For example, with the function provided:
const func = function() {
alert("Hello world!");
};
Both methods would work identically for this simple case since it doesn’t take arguments:
func.call(null); // Works fine
func.apply(null); // Also works fine
However, the difference becomes apparent with arguments:
function greet(name, greeting) {
console.log(`${greeting}, ${name}!`);
}
// Using call() with individual arguments
greet.call(null, "Alice", "Hello");
// Using apply() with array of arguments
greet.apply(null, ["Bob", "Hi"]);
According to the MDN documentation, these methods are fundamentally the same in how they pass arguments to the called function - the definition inside the function differs.
Performance Considerations
When it comes to performance, several sources consistently indicate that call() is generally faster than apply(), though the difference is often minimal.
Performance Benchmarks
Based on Stack Overflow discussions, call() shows better performance results in benchmarks:
- call() performs better because it doesn’t need to handle array-arguments
- The performance difference is most noticeable in performance-critical code
- However, as noted in the research, the actual performance of a minuscule operation like this is dependent on the algorithm that uses it
When Performance Matters
For simple function calls with known arguments, using the function directly is faster than using apply(), as mentioned in the CodeLucky JavaScript Function Apply guide. The performance difference becomes significant only in:
- High-frequency function calls (like in loops)
- Performance-critical applications
- Large-scale applications calling these methods millions of times
Modern JavaScript Impact
With the introduction of spread syntax, the performance landscape has changed. Modern JavaScript engines optimize spread syntax effectively, making it a competitive alternative to apply() in many scenarios.
Use Cases and Scenarios
The choice between call() and apply() depends largely on your use case and how arguments are structured.
When to Use call()
call() is best when:
- You have a fixed number of known arguments
- Arguments are already available as separate variables
- You’re working with method borrowing and need to pass individual arguments
Example from the GeeksforGeeks documentation:
function add(a, b) {
return a + b;
}
// Using call() with individual arguments
const result = add.call(null, 5, 3); // result = 8
When to Use apply()
apply() shines when:
- You’re working with arrays of arguments
- You have an unknown number of arguments
- You’re working with the arguments object or array-like objects
- You need to concatenate arrays
As noted in the Reddit discussion, apply is best when dealing with a fixed number of arguments, apply shines when handling arrays or an unknown number of arguments.
Array Operations
apply() has been traditionally used for array operations, as shown in the MDN documentation:
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
Practical Examples
Let’s explore concrete examples demonstrating when each method is appropriate.
Method Borrowing Example
Both call() and apply() allow you to borrow methods from other objects:
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
const user = {
firstName: "John",
lastName: "Doe"
};
// Using call()
console.log(person.fullName.call(user)); // "John Doe"
// Using apply() with array arguments
console.log(person.fullName.apply(user)); // "John Doe"
Dynamic Function Invocation
When you need to invoke a function dynamically with arguments from an array:
function calculate(a, b, operation) {
switch(operation) {
case 'add': return a + b;
case 'subtract': return a - b;
case 'multiply': return a * b;
case 'divide': return a / b;
default: return 0;
}
}
const numbers = [10, 5];
const operation = 'multiply';
// Using apply() with array arguments
const result = calculate.apply(null, [...numbers, operation]);
console.log(result); // 50
Working with Arguments Object
apply() is particularly useful with the arguments object:
function sum() {
return Array.prototype.reduce.call(arguments, (acc, val) => acc + val, 0);
}
// Using apply() to pass arguments object
console.log(sum.apply(null, [1, 2, 3, 4, 5])); // 15
Array Concatenation
As mentioned in the MDN documentation, apply() can be used for array operations:
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
// Using apply() to concatenate arrays
Array.prototype.push.apply(array1, array2);
console.log(array1); // [1, 2, 3, 4, 5, 6]
Modern Alternatives
With the introduction of ES6 spread syntax, many traditional apply() use cases have been replaced.
Spread Syntax vs apply()
Modern JavaScript allows using spread syntax (…) which provides similar functionality to apply():
function greet(name, greeting) {
console.log(`${greeting}, ${name}!`);
}
const args = ["Charlie", "Hello"];
// Using spread syntax (modern alternative)
greet(...args);
// Equivalent to apply()
greet.apply(null, args);
As noted in the Stack Overflow discussion, spread syntax has reduced the need for apply() in many cases, though apply() remains useful for:
- Older browser compatibility
- Non-iterable array-like objects
- Codebases that haven’t migrated to modern syntax
When to Still Use apply()
According to the John Kavanagh article, apply() remains useful in cases where:
- The array-like object isn’t a proper array
- You’re working with an older JavaScript codebase
- You need compatibility with older JavaScript engines
Conclusion
The key differences between JavaScript’s call() and apply() methods boil down to argument handling:
- call() accepts arguments individually, making it ideal when you have a fixed number of known parameters
- apply() accepts arguments as an array, perfect for dynamic scenarios with unknown numbers of arguments or array-like objects
- Performance-wise, call() is slightly faster due to the absence of array-argument overhead, though the difference is often negligible
- Modern spread syntax (…x) has reduced apply() usage but it remains valuable for legacy code and specific edge cases
Choose call() when you have predefined arguments and want the cleanest syntax. Choose apply() when working with arrays, the arguments object, or when you need maximum flexibility with argument handling. Understanding when to use each method will help you write more efficient and readable JavaScript code.
Sources
- MDN - Function.prototype.call()
- MDN - Function.prototype.apply()
- Stack Overflow - What is the difference between call and apply?
- Stack Overflow - JavaScript performance: Call vs Apply
- GeeksforGeeks - Difference between Function.prototype.apply and Function.prototype.call
- Medium - JavaScript Function Methods: Call vs Apply vs Bind
- Reddit - Function invocation…why use .call() and .apply()?
- CodeLucky - JavaScript Function Apply
- John Kavanagh - Understanding prototype.apply() in JavaScript