Question
JavaScript call() vs apply(): Difference, Use Cases, and Examples
Question
In JavaScript, what is the difference between using Function.prototype.apply() and Function.prototype.call() to invoke a function?
const func = function() {
alert("Hello world!");
};
func.apply();
func.call();
Are there any performance differences between these two methods? When is it better to use call() instead of apply(), and when should apply() be preferred?
Short Answer
By the end of this page, you will understand how call() and apply() invoke a function, how they set this, how they pass arguments differently, and when each one is useful in JavaScript code.
Concept
call() and apply() are both methods available on JavaScript functions. They let you invoke a function immediately while also controlling what this should refer to inside that function.
The core difference is how arguments are passed:
call(thisArg, arg1, arg2, arg3)passes arguments one by one.apply(thisArg, [arg1, arg2, arg3])passes arguments as an array or array-like object.
Why this matters
In JavaScript, this depends on how a function is called. Sometimes you want to borrow a function from one object and use it with another object, or call a function when your arguments already exist in an array. That is where call() and apply() are useful.
Important idea
If a function takes no arguments, then these two are effectively the same in everyday use:
func.call();
func.apply();
Both invoke the function immediately.
Performance note
In modern JavaScript, performance differences between call() and apply() are usually negligible for normal code. You should choose based on clarity and argument format, not micro-optimizations.
Modern JavaScript note
Today, if you already have an array of arguments, spread syntax is often preferred over apply():
fn.call(obj, ...args);
// or simply
fn(...args);
So while apply() is still important to understand, spread syntax often replaces it in modern code.
Mental Model
Think of a function as a worker who needs two things before starting:
- Who they are working for → this is
this - What materials they are given → these are the arguments
call() says:
"Work for this person, and here are your materials one by one."
apply() says:
"Work for this person, and here is a single box containing all your materials."
So the job is the same. The only real difference is how the materials are handed over.
call()= separate argumentsapply()= one array of arguments
Syntax and Examples
Basic syntax
fn.call(thisArg, arg1, arg2, arg3);
fn.apply(thisArg, [arg1, arg2, arg3]);
thisArgis the value thatthisshould refer to inside the function.- The remaining values are the function arguments.
Example 1: No arguments
function greet() {
console.log("Hello world!");
}
greet.call();
greet.apply();
Both lines do the same thing here because:
- no custom
thisis needed - no arguments are being passed
Example 2: Setting this
function introduce() {
console.log(`Hi, I am ${this.name}`);
}
const person = { name: "Ava" };
introduce.call(person);
introduce.apply(person);
Both print:
Hi, I am Ava
Example 3: Passing arguments
function add(a, b) {
return a + b;
}
console.log(add.call(null, 2, 3)); // 5
console.log(add.apply(null, [2, 3])); // 5
Here the difference is visible:
call()takes2, 3apply()takes[2, 3]
Example 4: Useful case for apply()
function sum(a, b, c) {
return a + b + c;
}
const numbers = [10, 20, 30];
console.log(sum.apply(null, numbers)); // 60
This is convenient when arguments are already stored in an array.
Modern alternative with spread
console.log(sum(...numbers)); // 60
This is often easier to read in modern JavaScript.
Step by Step Execution
Consider this example:
function showMessage(greeting, punctuation) {
console.log(greeting + ", " + this.name + punctuation);
}
const user = { name: "Lina" };
showMessage.call(user, "Hello", "!");
showMessage.apply(user, ["Hello", "!"]);
What happens with call()
showMessage.call(user, "Hello", "!");
Step by step:
- JavaScript looks at the function
showMessage. call()invokes it immediately.thisinsideshowMessagebecomesuser.- The first argument becomes
greeting = "Hello". - The second argument becomes
punctuation = "!". - The output is:
Hello, Lina!
What happens with apply()
showMessage.apply(user, ["Hello", "!"]);
Step by step:
- JavaScript looks at the function
showMessage. apply()invokes it immediately.thisinsideshowMessagebecomesuser.- JavaScript takes the array
["Hello", "!"]and unpacks it into arguments. greeting = "Hello"punctuation = "!"- The output is the same:
Hello, Lina!
Key takeaway
The function execution is the same. Only the argument-passing style is different.
Real World Use Cases
1. Reusing a method with another object
const person1 = {
name: "Sam",
sayName() {
console.log(this.name);
}
};
const person2 = { name: "Rita" };
person1.sayName.call(person2); // Rita
This is called function borrowing.
2. Calling a function with array data
function multiply(a, b, c) {
return a * b * c;
}
const values = [2, 3, 4];
multiply.apply(null, values); // 24
Useful when arguments come from:
- API responses
- form data
- parsed CSV rows
- dynamic configuration arrays
3. Converting array-like data in older patterns
Historically, apply() was often used with array-like objects such as arguments.
function logAll() {
console.log(Math.max.apply(null, arguments));
}
Today, rest parameters are usually cleaner:
function logAll(...args) {
console.log(Math.max(...args));
}
4. Wrapper functions and delegation
A function may pass work to another function while preserving context.
function greet(name) {
console.log(this.prefix + " " + name);
}
const context = { prefix: "Hello" };
greet.call(context, "Mia");
Real Codebase Usage
In real projects, call() and apply() appear less often than basic function calls, but they still show up in useful patterns.
1. Method borrowing
Developers sometimes reuse built-in methods on array-like values.
const arrayLike = { 0: "a", 1: "b", length: 2 };
const result = Array.prototype.join.call(arrayLike, "-");
console.log(result); // a-b
2. Delegating arguments
A wrapper function may forward all received arguments.
function wrapper() {
return originalFunction.apply(this, arguments);
}
In modern JavaScript this is usually written as:
function wrapper(...args) {
return originalFunction.call(this, ...args);
}
3. Explicit context control
When code depends on this, developers may use call() to make that connection explicit.
function save() {
if (!this.id) {
throw new Error("Missing id");
}
console.log("Saving", this.id);
}
const record = { id: 42 };
save.call(record);
4. Guarding and validation before invocation
A function can validate inputs, then invoke another function with a chosen context.
function safeInvoke(fn, context, args) {
if (typeof fn !== "function") {
throw new TypeError("fn must be a function");
}
return fn.apply(context, args);
}
5. Migration to spread syntax
In modern codebases, many older apply() usages are replaced with spread syntax because it is easier to read.
const numbers = [5, 8, 2];
Math.max(...numbers);
But understanding apply() is still helpful when reading older code or library internals.
Common Mistakes
1. Forgetting that call() and apply() invoke immediately
Some beginners think these methods just prepare a function. They do not. They run it right away.
function sayHi() {
console.log("Hi");
}
sayHi.call(); // runs now
sayHi.apply(); // runs now
2. Passing array arguments to call() by mistake
Broken code:
function add(a, b) {
return a + b;
}
console.log(add.call(null, [2, 3])); // wrong
Why it fails:
abecomes[2, 3]bbecomesundefined
Correct versions:
add.call(null, 2, 3);
add.apply(null, [2, 3]);
3. Passing separate values to apply()
Broken code:
add.apply(null, 2, 3); // wrong
Correct:
add.apply(null, [2, 3]);
4. Misunderstanding this with arrow functions
Arrow functions do not have their own this in the same way regular functions do. Using call() or apply() on an arrow function usually does not change this as expected.
const show = () => {
console.log(this);
};
show.call({ name: "Test" });
This will not bind this like a regular function would.
Use a regular function if you need dynamic this:
function show() {
console.log(this);
}
show.call({ name: "Test" });
5. Using apply() when spread is clearer
Older style:
Math.max.apply(null, numbers);
Modern style:
Math.max(...numbers);
Prefer the clearer option unless you specifically need apply().
6. Assuming meaningful performance differences
For typical applications, choosing one over the other for speed is not worthwhile. Choose based on readability and argument shape.
Comparisons
| Feature | call() | apply() |
|---|---|---|
| Invokes function immediately | Yes | Yes |
Sets this | Yes | Yes |
| Argument format | Separate arguments | Array or array-like object |
| Good when arguments are already in an array | No | Yes |
| Good when arguments are known individually | Yes | Less convenient |
| Common modern replacement | fn.call(obj, ...args) | fn(...args) or fn.call(obj, ...args) |
call() vs normal function call
| Style | Example | When used |
|---|---|---|
| Normal call | greet("Sam") | Most common case |
call() | greet.call(user, "Sam") | When you need to control this |
apply() | greet.apply(user, ["Sam"]) | When you need to control this and have arguments in an array |
apply() vs spread syntax
| Style | Example | Notes |
|---|---|---|
apply() | fn.apply(obj, args) | Older but still valid |
| Spread | fn.call(obj, ...args) | Often clearer in modern JavaScript |
| Direct spread | fn(...args) | Best when this does not matter |
Cheat Sheet
Quick rules
call()andapply()both invoke a function immediately.- Both let you choose the value of
this. - Main difference: how arguments are passed.
Syntax
fn.call(thisArg, arg1, arg2, arg3);
fn.apply(thisArg, [arg1, arg2, arg3]);
Use call() when
- you know the arguments individually
- you want a straightforward function invocation with a custom
this
fn.call(obj, 1, 2, 3);
Use apply() when
- your arguments already exist in an array
- you are working with array-like objects in older code
fn.apply(obj, [1, 2, 3]);
Modern alternatives
fn.call(obj, ...args);
fn(...args);
Important notes
- If there are no arguments,
call()andapply()behave the same for most practical purposes. - Arrow functions do not respond to
thisrebinding the same way regular functions do. - Performance differences are usually insignificant in real applications.
FAQ
What is the main difference between call() and apply() in JavaScript?
The main difference is argument passing:
call()passes arguments one by oneapply()passes them as an array or array-like object
Do call() and apply() both change this?
Yes. Both let you set the this value for the function call.
Is call() faster than apply()?
In modern JavaScript engines, any performance difference is usually too small to matter in normal application code.
When should I use apply()?
Use apply() when your arguments are already in an array or array-like object.
When should I use call()?
Use call() when you want to pass arguments individually and set this explicitly.
Is apply() outdated?
Not outdated, but many of its common uses are now replaced by spread syntax in modern JavaScript.
Can call() or apply() change this for arrow functions?
No, not in the usual way. Arrow functions capture this from their surrounding scope.
Mini Project
Description
Build a small utility that formats user messages by calling the same function with different this values and argument styles. This demonstrates how call() and apply() work in practical code.
Goal
Create a reusable message formatter that can be invoked with different user objects using both call() and apply().
Requirements
- Create a function that uses
this.nameinside its output. - Invoke the function once with
call()and once withapply(). - Pass the message parts as separate arguments in one case and as an array in the other.
- Print the results to the console.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.