Explain Codes LogoExplain Codes Logo

What is the difference between call and apply?

javascript
functions
callbacks
this-context
Anton ShumikhinbyAnton Shumikhin·Mar 11, 2025
TLDR

call and apply are methods in JavaScript core purpose of which is invoking functions with specific this context. The key difference between the two lies in how they handle function parameters: call expects its arguments in a comma-separated list, while apply wants them within an array.

function greet(language, greeting) { console.log(greeting + ', I speak ' + language); } // Using call greet.call(this, 'JavaScript', 'Hello world'); // Hello world, I speak JavaScript // Using apply greet.apply(this, ['TypeScript', 'Hola']); // Hola, I speak TypeScript

You typically**call** when you are dealing with a known number of arguments, and apply when working with an array of arguments (helpful when it's not clear how many there will be).

Scenario-based breakdown

When to dial call

call shines when you have discrete arguments readily available:

const superhero1 = { name: 'Heisenberg' }; const superhero2 = { name: 'Pinkman' }; function introduce() { console.log(`I am the one who ${this.name}s!`); // Yup, I used a name as a verb } // Calling the function introduce.call(superhero1); // Breaking bad memes, anyone?

When to ring up apply

On the flip side, apply comes handy with arguments that are already in an array, or when the count of arguments is undetermined:

function sumUp() { return Array.prototype.reduce.call(arguments, (accumulator, currentNum) => accumulator + currentNum, 0); } const numbers = [1, 2, 3]; // Using apply console.log(sumUp.apply(null, numbers)); // 6, because math.

Enhancements through ES6

In ES6 environments, you can use the spread operator with call for cleaner and leaner code:

// ES6 spread with call console.log(sumUp.call(null, ...numbers)); // Still 6. Math is consistent like that.

Advanced considerations and best practices

Efficient argument passing

  • When forwarding arguments in decorators or event handlers, apply often provides a more efficient and natural flow.
  • If performance happens to be crucial, call might turn out to be marginally faster due to direct argument passing, avoiding any array handling overhead.

Performance impact – not a biggie

In most applications, the performance difference between call and apply is negligible at best. Unless you are Facebook or Google dealing with petabytes of user interactions, you won't even notice it. Prioritize writing code that's readable and expresses your intent.

Making sense of this in JavaScript

Both call and apply allow you to control the this context. This ability is fundamental in certain scenarios like object-oriented programming, functional programming, or simply function decoration.

Keeping context consistent

In situations where this can change depending on context (like callback functions), call or apply can ensure the context stays consistent:

function callback() { console.log(`Handled by ${this.handlerName}`); } const handler = { handlerName: 'clickHandler', handleClick(buttonId) { document.getElementById(buttonId).addEventListener('click', callback.bind(this)); } }; handler.handleClick('myButton'); // 'Handled by clickHandler' on click

Visual representation

Just imagine these methods are very much akin to a normal phone (📞) operation:

  • For call — imagine every argument as each individual digit dialed one at a time.
func.call(context, arg1, arg2);
  • For apply — consider every argument as a pre-saved contact dialled in one go:
func.apply(context, [arg1, arg2]);

Other aspects and interesting tidbits

Code clarity and function semantics

  • Even when not passing any arguments, use call to stress the function isn't invoked in a traditional manner but with a personalized this context.

Dynamic function invocations

  • For complex scenarios like variadic functions (those accepting a varying number of arguments), apply often makes your code more readable and maintainable.

Safeguarding memory

  • With large arrays, sticking with call along with the ES6 spread operator could help avoid potential memory issues that apply could introduce due to its penchant for array handling.

Powering method chaining

  • For fluent, chained interfaces, call can be a better choice as it returns the return value of the function it’s invoking - very handy for chaining!