When to Use JS bind vs call vs apply: Full Guide
bind, call, and apply all set this explicitly, but they work differently. Learn exactly when to use each one, how partial application works, and the modern spread alternative to apply.
JavaScript bind vs call vs apply is a question every developer runs into once they need to control what this points to. All three are methods on Function.prototype for setting this explicitly, but call and apply invoke the function right away while bind returns a new function for later use.
| call | apply | bind | |
|---|---|---|---|
| Invokes immediately? | Yes | Yes | No, returns new function |
| How arguments are passed | Individually | As an array | Individually, pre-set |
| Use case | Borrow a method once | Spread array as arguments | Create a permanently bound function |
call: Invoke Now with Individual Arguments
The call method executes a function right away, with this set to the first argument and remaining arguments passed individually. It is the tool to reach for when you already know how many arguments you have.
function introduce(greeting, punctuation) {
return `${greeting}, I am ${this.name}${punctuation}`;
}
const user = { name: "Alice" };
console.log(introduce.call(user, "Hello", "!")); // "Hello, I am Alice!"The most common use of call is borrowing a method from one object to use on another, without adding that method to the second object.
const alice = {
name: "Alice",
greet() { return `Hi from ${this.name}`; }
};
const bob = { name: "Bob" };
console.log(alice.greet.call(bob)); // "Hi from Bob"Bob does not have a greet method of his own, but call lets you run alice.greet with bob as this for a single invocation. The method is borrowed, not copied.
apply: Invoke Now with Array Arguments
The apply method behaves identically to call except it takes arguments as a single array, or array-like object, instead of listing them individually.
function introduce(greeting, punctuation) {
return `${greeting}, I am ${this.name}${punctuation}`;
}
const user = { name: "Alice" };
const args = ["Hello", "!"];
console.log(introduce.apply(user, args)); // "Hello, I am Alice!"The classic use of apply is with functions like Math.max that accept variable arguments but not an array directly. Passing an array straight to Math.max would not work, since it expects separate number arguments rather than one array argument.
const scores = [42, 17, 89, 3, 65];
const highest = Math.max.apply(null, scores);
console.log(highest); // 89Math.max expects individual numbers, so apply spreads the array into individual arguments. In modern code, the spread operator does the same thing more clearly: Math.max(...scores). Reach for apply instead of spread when you have an array-like object that is not iterable, or when you need to set this and spread arguments in the same call.
bind: Return a New Function for Later
The bind method does not invoke the function. It returns a new function with this permanently locked to the first argument, and any additional arguments pre-filled through partial application.
function introduce(greeting) {
return `${greeting}, I am ${this.name}`;
}
const user = { name: "Alice" };
const boundIntroduce = introduce.bind(user);
console.log(boundIntroduce("Hello")); // "Hello, I am Alice"
console.log(boundIntroduce("Hey")); // "Hey, I am Alice"boundIntroduce is a brand new function, and every time you call it, this is always user. This makes bind the standard fix for the losing-this problem with callbacks like setTimeout.
const button = {
text: "Click me",
handleClick() { console.log(this.text); }
};
// setTimeout(button.handleClick, 1000); // this is lost, logs undefined
setTimeout(button.handleClick.bind(button), 1000); // "Click me"Partial Application with bind
Arguments after the this value are pre-filled into the returned function, and any arguments you pass later are appended after those.
function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
const triple = multiply.bind(null, 3);
console.log(double(5)); // 10
console.log(triple(5)); // 15When this does not matter, pass null as the first argument so only the partial application behavior is used.
When to Use Which
The diagram captures the whole decision: reach for bind when you need the function again later, apply or spread when your arguments already live in an array, and call for a one-time invocation with known arguments.
- Use call when you need to invoke a function immediately with a specific this and a known, fixed number of arguments, such as borrowing a method for a single use.
- Use apply when your arguments are already in an array or array-like object, or when working with variadic functions like Math.max.
- Use bind when you need a function to call later with a fixed this, such as event handlers or setTimeout callbacks, or when you want partial application.
bind Is Permanent
Once a function is bound, you cannot change its this. Calling bind again on an already-bound function ignores the new this argument entirely.
function getValue() {
return this.value;
}
const boundTo42 = getValue.bind({ value: 42 });
const rebound = boundTo42.bind({ value: 99 });
console.log(boundTo42()); // 42
console.log(rebound()); // 42, the second bind is ignoredThe new operator is the one exception: it can override a bound function's this. When a bound function is used as a constructor, the bound this is ignored and a fresh object takes its place.
function Person(name) {
this.name = name;
}
const BoundPerson = Person.bind(null, "Default");
const p = new BoundPerson();
console.log(p.name); // "Default", the pre-filled argument still appliesArrow Functions vs bind
Arrow functions do not have their own this. They capture it from the enclosing scope, which is often a cleaner alternative to bind for callbacks.
class Timer {
constructor() {
this.seconds = 0;
}
start = () => {
setInterval(() => this.seconds++, 1000);
};
}The start field above is an arrow function, so this stays bound to the Timer instance automatically, without needing a manual bind call anywhere.
| Approach | Best for |
|---|---|
fn.bind(this) | Passing an existing method as a callback |
| Arrow function wrapper | A one-off inline callback |
| Arrow function class field | A method you will hand off repeatedly, such as an event handler |
For more on how this is determined at each of these call sites, see the this keyword. For the constructor case shown above with bind and new, see constructor functions.
Rune AI
Key Insights
- call(thisArg, arg1, arg2): invokes immediately, arguments passed individually.
- apply(thisArg, [args]): invokes immediately, arguments passed as an array.
- bind(thisArg, arg1, arg2): returns a new function, does not invoke immediately.
- Use modern spread syntax (...args) instead of apply when you do not need to set this.
- bind is permanent: a bound function cannot be rebound, and new overrides bind's this.
Frequently Asked Questions
Can I use the spread operator instead of apply?
Does bind work on arrow functions?
Can I rebind an already bound function?
Conclusion
call invokes immediately with individual arguments. apply invokes immediately with array arguments. bind returns a new function for later invocation. Use call when you have a fixed number of arguments. Use apply (or spread) when arguments are in an array. Use bind when you need a reusable function with a locked this or preset arguments. The modern spread operator replaces apply in many cases, but all three remain essential tools for controlling this in JavaScript.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.