call, apply, and bind
Three ways to control what this refers to when a function runs.
Loading visual…
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 laterbind 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.
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.