call() vs apply()
The Short Answer
Both call() and apply() are methods that allow you to execute a function with a specified this context and arguments. They enable you to control what the this keyword refers to inside the function being called.
The only difference between them is how they handle arguments: call() takes arguments individually (comma-separated), while apply() takes them as a single array.
How They Work
In the example below, person has an introduce method that uses this.name. When we call it normally, this refers to person. But using call() or apply(), we can redirect this to point at employee instead — so the same function now uses Sarah's name. The only difference between the two is whether you pass arguments as a comma-separated list or as an array.
const person = {
name: 'John',
introduce: function (role: string, department: string) {
return `Hello, I'm ${this.name}, ${role} in ${department}`;
},
};
const employee = {
name: 'Sarah',
};
// Without call/apply — this refers to person
person.introduce('Engineer', 'Frontend');
// → "Hello, I'm John, Engineer in Frontend"
// With call/apply — this now refers to employee
person.introduce.call(employee, 'Manager', 'Sales');
// → "Hello, I'm Sarah, Manager in Sales"
person.introduce.apply(employee, ['Manager', 'Sales']);
// → "Hello, I'm Sarah, Manager in Sales"
Both methods achieve the same outcome. The first argument is always the object you want this to refer to. The remaining arguments are passed to the function being called.
The Difference Between call and apply
The code below shows the same function called two ways. With call(), you pass arguments one by one after the context object. With apply(), you wrap them in an array. The result is identical — it's purely a matter of which format your arguments are already in.
const person = {
name: 'John',
introduce: function (role, department) {
return `Hello, I'm ${this.name}, ${role} in ${department}`;
},
};
const employee = {
name: 'Sarah',
};
// Using call() - arguments are passed individually
person.introduce.call(employee, 'Manager', 'Sales');
// Returns: "Hello, I'm Sarah, Manager in Sales"
// Using apply() - arguments are passed as an array
person.introduce.apply(employee, ['Manager', 'Sales']);
// Returns: "Hello, I'm Sarah, Manager in Sales"
Both methods achieve the same outcome, with the choice between them typically depending on whether your arguments are available as separate values or as an array.
Memory trick
call = Commas (arguments separated by commas). apply = Array (arguments wrapped in an array). The first letter gives it away.
Practical Use Cases
The code below shows three real-world scenarios where call() and apply() shine. The first uses apply() to spread an array into Math.max (which normally expects individual arguments). The second uses call() to borrow Array's slice method on an array-like object that doesn't have it. The third uses call() to invoke a parent constructor with the child's this.
// 1. Finding max in an array (apply spreads the array)
const numbers = [5, 6, 2, 3, 7];
Math.max.apply(null, numbers); // 7
// Math.max expects individual args: Math.max(5, 6, 2, 3, 7)
// apply() spreads the array into individual arguments
// 2. Borrowing methods from another object
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
const realArray = Array.prototype.slice.call(arrayLike);
// → ['a', 'b', 'c']
// 3. Calling a parent constructor
function Animal(name: string) {
this.name = name;
}
function Dog(name: string, breed: string) {
Animal.call(this, name); // Call parent with Dog's this
this.breed = breed;
}
Modern Alternatives
With ES6+, the spread operator (...) handles most cases where you'd previously reach for apply(). The code below shows three common patterns side by side — the old apply()/call() way and the modern spread/Array.from equivalent. In each case, the modern version is shorter and more readable.
// Finding max — apply() vs spread
Math.max.apply(null, numbers); // old way
Math.max(...numbers); // modern way
// Converting array-like objects
Array.prototype.slice.call(arguments); // old way
Array.from(arguments); // modern way
[...arguments]; // also modern
// Merging arrays
Array.prototype.push.apply(arr1, arr2); // old way
arr1.push(...arr2); // modern way
However, call() is still commonly used when you need to borrow a method with a different this context — there's no spread-based shortcut for that.
Why Interviewers Ask This
This question tests your understanding of the this keyword and function invocation in JavaScript. Interviewers want to see that you know both methods exist, understand the subtle difference in argument passing, and can identify when each is appropriate. Mentioning modern alternatives like the spread operator shows you stay current with the language.
Quick Revision Cheat Sheet
call(): Invokes immediately, arguments passed one by one: fn.call(ctx, a, b)
apply(): Invokes immediately, arguments passed as array: fn.apply(ctx, [a, b])
Both set this: First argument is always the this context for the function
Memory trick: Call = Commas, Apply = Array
Modern alternative: Spread operator (...) often replaces apply() for passing arrays