4. Call, Apply, And Bind In JavaScript


4.1 Why Manually Change the this
Value in a Function
Because the value of this
is dynamic, depending on how the function is called, rather than being static. Here are a few common use cases that explain why we need to manually adjust the value of this
:
1 this
in Event Handler Functions
In event handler functions, this
by default refers to the DOM element that triggered the event, not the object we defined. We may want to access our own object inside the event handler instead of the DOM element, and in that case, we need to manually adjust the value of this
.
const button = document.querySelector('button');
const person = {
name: 'Alice',
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
button.addEventListener('click', person.greet); // `this` refers to the button element
2 Function Reusability and Borrowing
Sometimes, we need to borrow methods from other objects or reuse a method to handle different objects. In such cases, if we don't manually set this
, the function's behavior may not work as expected.
const person = {
name: 'Bob',
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
const animal = {
name: 'Cat'
};
// Calling greet directly will cause this to point incorrectly.
person.greet(); // Output:Hello, I'm Bob
const greetAnimal = person.greet;
greetAnimal(); // Output:Hello, I'm undefined(`this` do not point to person)
Here, when greetAnimal()
is called, this
by default refers to the global object (which is window
in the browser, or undefined
in strict mode).
3 this
in Timers and Callback Functions
When using setTimeout
or other asynchronous operations, this
usually doesn't refer to the object you expect, because the callback function is invoked in a different execution context.
const obj = {
name: 'Alice',
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
setTimeout(obj.greet, 1000); // Output:Hello, I'm undefined
4 this
in Class Instances
In a class, the this
keyword inside a method by default refers to the class instance. However, if you pass a class method to an external function and want to retain the reference to the instance, you must manually bind this
.
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
}
const person = new Person('Bob');
const greetPerson = person.greet;
greetPerson(); // Output:Hello, I'm undefined(`this` do not refer to the person instance)
4.2 Manually set this
using call
, apply
, and bind
call
, apply
, and bind
are three commonly used function methods in JavaScript, used to manually change the value of this
inside a function.
Methods | Whether to execute immediately | Parameter format | Return value |
call | ✅ | “ this “, Single parameter or multiple parameters | Execution result |
apply | ✅ | “ this “, Single array parameter | Execution result |
bind | ❌ | “ this “, Single parameter or multiple parameters | Return a new function |
4.3 Real-world analogy for call, apply, and bind
Imagine you're a director, and there's an "actor" (a function) who can wear different "costumes" (the this
context). If you want the actor to wear someone else's costume, you can use one of three methods — call
, apply
, or bind
— to change their appearance.
Character setup
function sayHello(greeting, ending) { // "actor"
console.log(`${greeting}, I'm ${this.name} ${ending}`);
}
const alice = { name: "Alice" }; // costume Alice
const bob = { name: "Bob" }; // costum Bob
call
Method
The director demands an immediate performance — the actor puts on the Alice costume and starts acting right away!
sayHello.call(alice, "Hi", "!");
// Output:Hi, I'm Alice !
apply
Method
The director demands an immediate performance, but the parameters are handed to the actor in a single "package".
sayHello.apply(bob, ["Hello", "!!!"]);
// Output:Hello, I'm Bob !!!
bind
Method
The director tells the actor to get into costume, but not to perform yet — wait until the cue, “Action!”, before starting.
const bobSayHello = sayHello.bind(bob, "Hey", "!!!");
// No output
bobSayHello(); // Output:Hey, I'm Bob !!!
4.4 Implementing A Custom bind
Function
first we need to store the original function that calls bind function
return a new function that can ensure that the new function
this
refers to the context we pass inthe arguments of bind function and new function can be combined
Function.prototype.myBind = function(context, ...args) {
// store the original function, this refers to the function that calls myBind
const originalFunction = this;
// return a new function
return function(...newArgs) {
// call the original function with the context and combined arguments
return originalFunction.apply(context, [...args, ...newArgs]);
}
}
function Person(greeting, ending) {
name = 'DuDu';
console.log(`${greeting}, I'm ${this.name} ${ending}`);
}
const Alice = {name: 'Alice'};
const NewPerson = Person.myBind(Alice, 'Hello');
NewPerson('Bye!'); // Hello, I'm Alice Bye!
Subscribe to my newsletter
Read articles from Huabin Zhang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
