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.

7 min read

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.

callapplybind
Invokes immediately?YesYesNo, returns new function
How arguments are passedIndividuallyAs an arrayIndividually, pre-set
Use caseBorrow a method onceSpread array as argumentsCreate 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.

javascriptjavascript
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.

javascriptjavascript
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.

javascriptjavascript
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.

javascriptjavascript
const scores = [42, 17, 89, 3, 65];
const highest = Math.max.apply(null, scores);
console.log(highest); // 89

Math.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.

javascriptjavascript
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.

javascriptjavascript
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.

javascriptjavascript
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)); // 15

When this does not matter, pass null as the first argument so only the partial application behavior is used.

When to Use Which

Decision flow for bind, call, and apply

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.

javascriptjavascript
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 ignored

The 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.

javascriptjavascript
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 applies

Arrow 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.

javascriptjavascript
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.

ApproachBest for
fn.bind(this)Passing an existing method as a callback
Arrow function wrapperA one-off inline callback
Arrow function class fieldA 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

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.
RunePowered by Rune AI

Frequently Asked Questions

Can I use the spread operator instead of apply?

Yes. In modern JavaScript, fn(...args) replaces fn.apply(null, args) in most cases. The spread operator is more readable. apply is still useful when you have an array-like object (not a true array) that is not iterable, or when you need to set both this and spread arguments simultaneously.

Does bind work on arrow functions?

Technically yes, but the this argument is ignored. Arrow functions have a fixed lexical this that cannot be changed by bind, call, or apply. The bound function is still created but this stays locked to the enclosing scope.

Can I rebind an already bound function?

No. A function created with bind has a permanently fixed this. Calling bind again on it creates another bound function, but the second this argument is ignored. The original binding always wins.

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.