call vs apply vs bind
All three set the "this" context of a function. call() and apply() invoke immediately (differing in argument format), while bind() returns a new function for later use.
Side-by-Side Comparison
| Feature | Function.call() | Function.apply() | Function.bind() |
|---|---|---|---|
| Invokes immediately | Yes | Yes | No (returns new function) |
| Argument format | Individual: fn.call(ctx, a, b) | Array: fn.apply(ctx, [a, b]) | Individual: fn.bind(ctx, a, b) |
| Partial application | No | No | Yes |
| Returns | Function result | Function result | New bound function |
Code Examples
Function.call()
- Invokes the function IMMEDIATELY
- First argument sets "this"
- Remaining arguments passed individually
- fn.call(context, arg1, arg2)
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`
}
const user = { name: 'Alice' }
greet.call(user, 'Hello', '!')
// "Hello, Alice!"Function.apply()
- Invokes the function IMMEDIATELY
- First argument sets "this"
- Second argument is an ARRAY of arguments
- fn.apply(context, [arg1, arg2])
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`
}
const user = { name: 'Alice' }
const args = ['Hello', '!']
greet.apply(user, args)
// "Hello, Alice!"
// Classic use: Math.max with array
Math.max.apply(null, [1, 5, 3]) // 5Function.bind()
- Returns a NEW function with "this" permanently set
- Does NOT invoke immediately
- Can partially apply arguments (partial application)
- Returned function can be called later
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`
}
const user = { name: 'Alice' }
const greetAlice = greet.bind(user)
greetAlice('Hello', '!') // "Hello, Alice!"
// Partial application
const hiAlice = greet.bind(user, 'Hi')
hiAlice('!') // "Hi, Alice!"When to Use Which
Function.call()
When you know the arguments and want to invoke immediately. Common for borrowing methods: Array.prototype.slice.call(arguments).
Function.apply()
When arguments are already in an array. Less common since spread syntax arrived: Math.max(...arr) replaces Math.max.apply(null, arr).
Function.bind()
When you need to pass a function with a specific "this" for later invocation — event handlers, callbacks, React class component methods.
Common Mistakes
- Using bind() in a render method creates a new function every render — bind in the constructor or use arrow functions instead
- Forgetting that apply() takes an array — passing individual args gives unexpected results
- Trying to rebind a bound function — bind() creates a permanent binding that cannot be overridden
Interview Questions
How has spread syntax reduced the need for apply()?
Math.max.apply(null, arr) is now Math.max(...arr). Function.apply(ctx, args) is now fn.call(ctx, ...args). Spread syntax is more readable and doesn't require the null context placeholder.
Implement Function.prototype.bind from scratch
Return a wrapper function that uses apply internally: function bind(context, ...boundArgs) { const fn = this; return function(...callArgs) { return fn.apply(context, [...boundArgs, ...callArgs]); }; }