原文地址:https://dev.to/bhagatparwinder/truly-understand-bind-call-apply-21da
Bind
JavaScript 中的 this
扮演者重要的角色,在 JavaScript 中它是依据函数是怎么被调用的而不是它在哪声明的(箭头函数则表现为相反)。
我们举一个例子来示范一下 this
是如何工作的:
const sayGreeting = {
name: "Parwinder",
hello: function() {
return `Hello, ${this.name}`;
}
}
console.log(sayGreeting.hello()); // Hello, Parwinder
hello
方法可以获取 sayGreeting
上的 name
属性,当我用 sayGreeting
调用它时,它是运行在 sayGreeting
对象上下文中的。
相反如果我这样做:
const sayGreeting = {
name: "Parwinder",
hello: function() {
return `Hello, ${this.name}`;
}
}
const hello = sayGreeting.hello;
console.log(hello === sayGreeting.hello); // true
console.log(hello()); // Hello, undefined
尽管 hello
变量与 sayGreeting
对象上的 hello
方法相等,但它的执行上下文并不是在 sayGreeting
中,而是在 window
或全局状态中。
bind
方法允许我们绑定上下文,它返回一个新的方法且上下文绑定为我们传递给 bind
函数的内容。
const sayGreeting = {
name: "Parwinder",
hello: function() {
return `Hello, ${this.name}`;
}
}
const hello = sayGreeting.hello.bind(sayGreeting);
console.log(hello()); // Hello, Parwinder
实际业务中哪里需要使用 bind?
上面的所有例子,数据的获取和方法的调用都在一个对象上 bind 的作用并不明显。可有时候当你需要向一个对象借一个方法但运行上下文需要在另一个对象中时,你就需要使用 bind
。
const sayGreeting = {
name: "Parwinder",
hello: function () {
return `Hello, ${this.name}`;
}
}
const nameObject = {
name: "Lauren"
}
const hello = sayGreeting.hello.bind(nameObject);
console.log(hello()); // Hello, Lauren
sayGreeting
对象上有 hello
方法,所以在 nameObject
对象上就没有必要再写一个相同的方法。我可以向 sayGreeting
对象借用它然后运行在 nameObject
上下文中。
Call
call
和 apply
与 bind
是有区别的,bind
返回一个新的方法而 call
和 apply
则立即调用执行方法。call
把 this
作为第一个参数,其他参数需要一个个的传递。它们都会传递到我们调用的函数中:
const sayGreeting = {
name: "Parwinder",
hello: function () {
return `Hello, ${this.name}`;
}
}
console.log(sayGreeting.hello.call(sayGreeting)); // Hello, Parwinder
带有其它参数:
const sayGreeting = {
name: "Parwinder",
hello: function (trait, color) {
return `Hello, ${this.name}. I see you ${trait} ${color}. It is my favorite too!`;
}
}
console.log(sayGreeting.hello.call(sayGreeting, "like", "red"));
// Hello, Parwinder. I see you like red. It is my favorite too!
Apply
尽管 apply
和 call
类似都是直接执行函数,但它接受的是一个数组作为第二个参数而不是逗号分隔的值。
const sayGreeting = {
name: "Parwinder",
hello: function () {
return `Hello, ${this.name}`;
}
}
console.log(sayGreeting.hello.apply(sayGreeting)); // Hello, Parwinder
当没有其余参数时 apply
和 call
没有区别,但是当我们有其余参数时,使用方法就有点区别:
const sayGreeting = {
name: "Parwinder",
hello: function (trait, color) {
return `Hello, ${this.name}. I see you ${trait} ${color}. It is my favorite too!`;
}
}
console.log(sayGreeting.hello.apply(sayGreeting, ["like", "red"]));
// Hello, Parwinder. I see you like red. It is my favorite too!
apply
使得传递多个参数变得更容易些,但是现在 ES6 中使用扩展运算符传递多个参数也很容易了。