Difference between call, apply, and bind in JavaScript

Intermediate12 min interview
Skills tested:
Explicit this binding with call and applyReturning a bound function with bind and partial applicationMethod borrowing from Array.prototypeWhy bind has no effect on arrow functionsChoosing the right method for a given invocation context

Advertisement

🧩 Scenario

In a real codebase, you will encounter call and apply when borrowing Array.prototype methods for array-like objects like the arguments object, NodeLists, and HTMLCollections. You will encounter bind when passing class methods as event callbacks or when implementing partial application of function arguments. In modern code, arrow functions and Array.from have reduced many use cases for these methods, but they remain important in legacy codebases and as a signal of deep JavaScript knowledge in interviews.

Architecture Walkthrough

call and apply: Invoke Immediately with a Custom this

call and apply both invoke a function immediately with a specified this value. The difference is only in how you pass arguments. call takes arguments as a comma-separated list after the first argument. apply takes arguments as a single array (or array-like) as the second argument.

A useful mnemonic: call accepts arguments like a regular function call, while apply accepts an array. In modern code, spread syntax (fn.call(ctx, ...args)) has mostly replaced apply, but understanding apply is important for reading legacy code and explaining the design.

bind: Return a New Permanently Bound Function

bind does not invoke the function. It returns a new function where this is permanently set to the provided value. No matter how the returned function is later called (as a method, as a callback, with call), its this cannot be changed after binding.

bind also supports partial application. Any arguments passed to bind after the first (this context) are pre-filled as leading arguments in the returned function. This makes bind useful for creating specialized versions of more general functions without writing additional wrapper code.

Arrow Functions Cannot Be Rebound

Arrow functions capture this from their lexical scope at definition time. They do not have their own this binding. Calling call, apply, or bind on an arrow function has no effect on this inside it. The first argument (the intended context) is silently ignored. This is a frequent source of confusion when developers try to rebind an arrow function method and see the original lexical this instead.


Key Code Explained

const user = { name: 'Ghazi', role: 'admin' };

function greet(greeting, punctuation) {
  console.log(`${greeting}, ${this.name}${punctuation}`);
}

// call: invoke immediately, arguments as comma-separated values
greet.call(user, 'Hello', '!'); // "Hello, Ghazi!"

// apply: invoke immediately, arguments as an array
greet.apply(user, ['Hi', '?']); // "Hi, Ghazi?"

// bind: returns a new function, does not invoke
const greetGhazi = greet.bind(user);
greetGhazi('Hey', '.'); // "Hey, Ghazi."

// bind with partial application: pre-fill the greeting argument
const greetGhaziHello = greet.bind(user, 'Hello');
greetGhaziHello('!'); // "Hello, Ghazi!"

// Method borrowing: use Array.prototype methods on array-like objects
function logAll() {
  const argsArray = Array.prototype.slice.call(arguments);
  console.log(argsArray.map(String));
}
logAll(1, true, null); // ["1", "true", "null"]

// Arrow function: bind has no effect on this
const arrowGreet = (greeting) => console.log(`${greeting}, ${this.name}`);
arrowGreet.call({ name: 'Ghazi' }, 'Hi'); // "Hi, undefined" — this is lexical

The arrow function example demonstrates the key gotcha. this.name resolves to the this of the scope where the arrow function was defined (likely undefined or the global object), not the object passed to call. The { name: 'Ghazi' } argument is silently discarded.


Tradeoffs

MethodInvokes immediatelyArgument passingReturns new function
callYesComma-separatedNo
applyYesArrayNo
bindNoPre-filled or deferredYes, permanently bound

What Interviewers Actually Check

  • Whether you can state the three-way difference between call, apply, and bind clearly and concisely
  • Whether you know why bind returns a new function instead of invoking the original
  • Whether you can write a method borrowing example and explain when it is needed
  • Whether you know bind supports partial application and can demonstrate it
  • Whether you know that call, apply, and bind have no effect on arrow functions

Follow-Up Questions

  1. In a React class component, why did developers call this.handleClick = this.handleClick.bind(this) in the constructor, and how do class field arrow functions avoid this?
  2. What does Function.prototype.call.call do and why is it confusing?
  3. How would you implement a simplified version of bind yourself using a closure?
  4. When bind is used inside a render method or a component render cycle, what performance concern arises?
  5. With optional chaining and modern destructuring available, are there any remaining legitimate use cases for apply in new code?

Common Candidate Mistakes

  • Trying to use bind on an arrow function to change this and not understanding why it has no effect
  • Confusing which method takes an array (apply) and which takes comma-separated arguments (call)
  • Not knowing that bind supports partial application and thinking it is only for fixing this
  • Forgetting to pass the context as the first argument to call when borrowing a method, causing this to be wrong inside the borrowed function
  • Creating a new bound function inside a render loop instead of binding once in the constructor or using a class field arrow function

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you state the invocation difference between call, apply, and bind from memory?
  • Can you write a method borrowing example using Array.prototype.slice.call?
  • Can you explain why bind returns a new function instead of invoking the original?
  • Can you demonstrate partial application using bind with pre-filled arguments?
  • Can you explain why call, apply, and bind have no effect on arrow functions?

Summary

call, apply, and bind all let you explicitly control what this refers to inside a function. call and apply invoke the function immediately with the provided context. The only difference between them is argument format: call takes arguments as individual values and apply takes them as an array. bind does not invoke the function; it returns a new function with this permanently fixed and optionally with leading arguments pre-filled.

The most common real-world use case for call and apply is method borrowing: using Array.prototype methods on array-like objects that do not have them natively. bind is most commonly used to ensure that class methods retain the correct this when passed as callbacks to event handlers or timers.

One important limitation: none of these methods work on arrow functions. Arrow functions have no this binding of their own, so any attempt to rebind them with call, apply, or bind is silently ignored.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

Do call, apply, and bind permanently change "this"?

Only bind() returns a new function with "this" permanently set. call() and apply() invoke immediately.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement