Difference between call, apply, and bind in JavaScript
Advertisement
🧩 Scenario
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
| Method | Invokes immediately | Argument passing | Returns new function |
|---|---|---|---|
| call | Yes | Comma-separated | No |
| apply | Yes | Array | No |
| bind | No | Pre-filled or deferred | Yes, 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
- 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? - What does
Function.prototype.call.calldo and why is it confusing? - How would you implement a simplified version of
bindyourself using a closure? - When
bindis used inside arendermethod or a component render cycle, what performance concern arises? - With optional chaining and modern destructuring available, are there any remaining legitimate use cases for
applyin new code?
Common Candidate Mistakes
- Trying to use
bindon an arrow function to changethisand not understanding why it has no effect - Confusing which method takes an array (apply) and which takes comma-separated arguments (call)
- Not knowing that
bindsupports partial application and thinking it is only for fixingthis - Forgetting to pass the context as the first argument to
callwhen borrowing a method, causingthisto 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, andbindfrom memory? - Can you write a method borrowing example using
Array.prototype.slice.call? - Can you explain why
bindreturns a new function instead of invoking the original? - Can you demonstrate partial application using
bindwith pre-filled arguments? - Can you explain why
call,apply, andbindhave 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.
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