在 JavaScript 中,this 关键字经常用于通过函数调用在运行时引用当前对象。然而,它也是令人头痛的问题之一,因为它的值取决于函数的调用方式。在默认情况下,this 指向全局对象 Window,但在另一种情况下,它可能会指向函数的调用者或它自己的实例。由于这样的不一致性,一个函数可能需要在执行时进行手动调整或重新分配。这就是我们介绍的 bind 函数可以派上用场的地方。
bind() 方法的通用用途是将函数的上下文分离出来,并为函数创建指定的 this 值。调用 bind() 函数时,它将返回一个新的函数,该函数的 this 值与上一个函数不同,并在执行时传递相同或新的参数。在本文中,我们将介绍如何使用 bind() 函数,以及为什么使用它可以使代码更具可读性和可维护性。
简单介绍
bind 函数的基本语法如下所示:
function.bind(thisArg[, arg1[, arg2[, ...]]])
在该例中,thisArg 是调用该函数时使用的 this 值。 arg1、arg2 等是在执行新函数时要传递的参数。bind() 方法返回一个新函数,该函数与原始函数相同,但 this 值已更改并有一个新的参数列表。
当有多个 bind() 函数将同一个函数绑定到不同的值时,函数的行为会变得非常困惑。所以最好选择一种在整个应用程序中使用的方法,以避免混淆。下面我们来看几个示例以更好地理解 bind() 函数的工作原理。
示例
让我们从一个简单的 JavaScript 类开始,该类包含一个属性 name 和一个方法 getName(),该方法返回 this.name。此时,类中的 this 值是指向当前类的实例的。
class Person {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
现在,让我们用不同的 this 上下文来调用该方法。我们将首先调用 getName() 方法,该方法在实例上定义,因此 this 关键字将使用 Person 类的上下文:
const michael = new Person('Michael');
console.log(michael.getName()); // 'Michael'
然后,我们可以使用 bind() 函数,在方法定义中将上下文绑定到全局对象:
const getName = michael.getName.bind(window);
console.log(getName()); // undefine
结果显然是不正确的,因为 window 对象没有一个名为 name 的属性。这个例子表明了当你改变 this 对象的内容时,你可以改变获取的数据,像上下文的名字一样。
现在,让我们看一看在事件处理程序的情况下如何使用 bind() 函数。在下面的示例中,添加一个 click 事件处理程序,该程序将绑定到下面的按钮元素:
const btn = document.querySelector('button');
btn.addEventListener('click', function(event) {
console.log(this.tagName); // button
});
由于按钮元素是事件处理程序的调用者,因此 this 关键字将指向该元素。然而,如果您使用 bind() 函数将上下文分离出来,并在事件处理程序中调用它,则 this 值将与按钮元素无关,以便您可以放心地使用它,如下所示:
const btn = document.querySelector('button');
const logTag = function() {
console.log(this.tagName); // button
}.bind(btn);
btn.addEventListener('click', logTag);
现在,当按钮被点击时,将会打印其 tagName 属性(即 "button") 。
在案例之前,让我们再看一个在对象中定义方法的示例。假设我们有一个 user 对象,包含一个属性 name 和一个方法 getName(),该方法返回 this.name。这就像之前示例中的 Person 类一样。
const user = {
name: 'Michael',
getName() {
return this.name;
}
};
但是,我们想让 getName() 方法在 Web Workers 或 Promise 中工作,因为这些环境中的 this 上下文显示为 Undefined,这使得在环境之间共享用户类变得更加困难。这时候,我们可以使用 bind() 函数来强制 getName() 在 user 对象中执行,如下所示:
const getName = user.getName.bind(user);
console.log(getName()); // 'Michael'
现在,无论在何种上下文中调用 getName(),它总是会在 user 对象中执行,并返回正确的名称。
结束语
在 JavaScript 中,this 关键字是一个强有力的工具,它可以使您的代码更优雅和可读。但是,如果不正确地使用 this,代码容易出现错误。这就是 bind() 函数可以大大改善代码的原因,因为它可以将对象的上下文分离出来,并创建可预测的 this 对象。同时也可以用于规范化回调函数作为事件处理程序的用例。如果您在写 JavaScript 并且尚未使用 bind() 函数,便是时候开始使用了。