← All concepts
A Closer Look at Functions

call, apply, and bind

Three ways to control what this refers to when a function runs.

Definition

Every function has access to call, apply, and bind, three methods for controlling what `this` refers to inside it. `fn.call(thisArg, arg1, arg2)` invokes fn immediately, with `this` set to thisArg and the remaining arguments passed in one by one. `fn.apply(thisArg, [arg1, arg2])` does the same thing, invoking fn right away with `this` set to thisArg, but takes the arguments as a single array instead of a list, which is convenient when the arguments are already collected in an array or the count varies. `fn.bind(thisArg, arg1)` behaves differently: it does not call fn at all. Instead it returns a brand new function with `this` (and optionally some leading arguments) permanently locked to what was passed in, ready to be called later, as many times as needed, with `this` never changing again regardless of how that new function is eventually invoked. One exception applies to all three: arrow functions ignore call, apply, and bind for the purpose of setting `this`, because an arrow function has no `this` of its own, it always uses `this` from the scope where it was defined.

Examples

function greet() {
  return `Hi, ${this.name}`;
}
greet.call({ name: "Ada" });  // "Hi, Ada"
greet.apply({ name: "Ada" }); // "Hi, Ada"

call and apply both run greet immediately with this pointed at the given object. With no extra arguments, they behave the same here.

function introduce(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}
introduce.call({ name: "Grace" }, "Hello", "!");
introduce.apply({ name: "Grace" }, ["Hello", "!"]);
// both: "Hello, Grace!"

call takes the extra arguments individually, apply takes them as one array. Both produce the same result, only the argument shape differs.

function greet() {
  return `Hi, ${this.name}`;
}
const boundGreet = greet.bind({ name: "Alan" });
// nothing runs yet
boundGreet(); // "Hi, Alan", called later

bind returns a new function with this locked to the given object. The original greet is untouched, and boundGreet can be called anywhere, any number of times, always with the same this.

Common mistakes

  • Mixing up call and apply's argument shape; call takes arguments one by one, apply takes them as a single array.
  • Expecting bind to run the function right away; bind only returns a new function, it does not call it.
  • Using call, apply, or bind on an arrow function to change this; arrow functions ignore all three and keep this from where they were defined.

Key takeaways

  • call and apply both invoke a function immediately with a chosen this; bind returns a new function for later.
  • call takes arguments individually, apply takes them as an array.
  • Arrow functions cannot have their this changed by call, apply, or bind.
Check your understanding

What does greet.bind({ name: 'Alan' }) do?

Where you see this

  • Locking this for a class method used as a callback, such as this.handleClick = this.handleClick.bind(this) in a constructor.
  • Borrowing an array method for an array-like object, like Array.prototype.slice.call(arguments) to turn arguments into a real array.
  • Calling a function with an argument list that is already an array, using apply instead of manually spreading it out.
  • Pre-filling some arguments of a function with bind to create a smaller, more specific function, like multiply.bind(null, 2) for double.

Practice this

Further reading

Previous
Currying
Next
Debounce and Throttle