Question

JavaScript call() vs apply(): Difference, Use Cases, and Examples

javascriptfunctionperformance

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:

  1. Who they are working for → this is this
  2. 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 arguments
  • apply() = one array of arguments
Take Quiz

Syntax and Examples

Basic syntax

fn.call(thisArg, arg1, arg2, arg3);
fn.apply(thisArg, [arg1, arg2, arg3]);
  • thisArg is the value that this should 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 this is 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() takes 2, 3
  • apply() 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:

  1. JavaScript looks at the function showMessage.
  2. call() invokes it immediately.
  3. this inside showMessage becomes user.
  4. The first argument becomes greeting = "Hello".
  5. The second argument becomes punctuation = "!".
  6. The output is:
Hello, Lina!

What happens with apply()

showMessage.apply(user, ["Hello", "!"]);

Step by step:

  1. JavaScript looks at the function showMessage.
  2. apply() invokes it immediately.
  3. this inside showMessage becomes user.
  4. JavaScript takes the array ["Hello", "!"] and unpacks it into arguments.
  5. greeting = "Hello"
  6. punctuation = "!"
  7. 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");
Take Quiz

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:

  • a becomes [2, 3]
  • b becomes undefined

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

Featurecall()apply()
Invokes function immediatelyYesYes
Sets thisYesYes
Argument formatSeparate argumentsArray or array-like object
Good when arguments are already in an arrayNoYes
Good when arguments are known individuallyYesLess convenient
Common modern replacementfn.call(obj, ...args)fn(...args) or fn.call(obj, ...args)

call() vs normal function call

StyleExampleWhen used
Normal callgreet("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

StyleExampleNotes
apply()fn.apply(obj, args)Older but still valid
Spreadfn.call(obj, ...args)Often clearer in modern JavaScript
Direct spreadfn(...args)Best when this does not matter
Take Quiz

Cheat Sheet

Quick rules

  • call() and apply() 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() and apply() behave the same for most practical purposes.
  • Arrow functions do not respond to this rebinding 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 one
  • apply() 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.

Take Quiz

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.name inside its output.
  • Invoke the function once with call() and once with apply().
  • Pass the message parts as separate arguments in one case and as an array in the other.
  • Print the results to the console.
Take Quiz

Keep learning

Related questions

View more