既然提到的文章帮助了你的答案,我试着从文章中提到重点,
在 JavaScript 中,绑定总是显式的,并且很容易丢失,因此使用 this 的方法不会在所有情况下都引用正确的对象,除非你强制它这样做。总的来说,JavaScript 中的绑定并不是一个困难的概念,但它经常被 JavaScripters 忽略或掩盖,从而导致混乱。
例子:
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark");
//=> "Hi Mark, my name is John"
再一次,
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
var fx = john.greet;
fx("Mark");
// => "Hi Mark, my name is "
这是 JavaScript 绑定中最重要的一个问题——我将其称为“绑定丢失”。每当您通过引用而不是直接通过其所有者对象访问方法时,都会发生这种情况。该方法失去了它的隐式绑定,并且 this 停止引用它的所有者对象并返回到它的默认值,在这种情况下是 window (所以如果 window 那时有一个 name 属性,它将被使用)。
识别绑定敏感的代码模式
绑定敏感代码模式涉及传递方法引用,这通常通过两种可能的方式发生:要么将方法作为值分配,要么将方法作为参数传递(这本质上是相同的,当你认为关于它)。
显式绑定
那么我们该如何解决呢?我们显式地绑定——也就是说,当 this 被调用时,我们显式地声明 this 将在方法中指向什么。我们如何做到这一点?JavaScript 为我们提供了两个选项:应用和调用。
var fx = john.greet;
fx.apply(john, ["Mark"]);
// => "Hi Mark, my name is John"
var fx = christophe.greet;
fx.call(christophe, "Mark");
// => "Hi Mark, my name is John"
所以我们想要的是一种持久绑定方法的方法,这样我们就可以得到一个绑定的方法引用。实现这一点的唯一方法需要我们将原始方法包装在另一个方法中,该方法将执行应用调用。这是一个尝试:
function createBoundedWrapper(object, method) {
return function() {
return method.apply(object, arguments);
};
}
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
var fx = createBoundedWrapper(john, john.greet);
fx("Mark");
// => "Hi Mark, my name is John"
如果你对 JavaScript 不太感兴趣,上面的代码可能会让你有点困惑。这里的想法是使用给定的对象和方法(可能属于所述对象)调用 createBoundedWrapper 将产生一个全新的函数(我们要返回的匿名函数)。
你应该绑定吗?
既然我们已经了解了绑定的细节,那么需要强调的是,有时候绑定是多余的。具体来说,有一种代码模式可以通过使用词法闭包来替换绑定,从而获得显着的性能收益。(如果你不清楚什么是闭包,不要惊慌。)
模式如下:方法中的一些代码依赖于通过引用传递给工作的匿名函数。该匿名函数需要访问周围方法的 this 关键字。例如,假设我们在数组中有每个迭代器,再次考虑以下代码:
// ...
processItems: function() {
this.items.each(function(item) {
// Process item…
this.markItemAsProcessed(item);
});
},
// ...
匿名方法可以被包裹起来,然后createBoundedWrapper
内部this
将指向外部范围的this
.
然而,这样的代码并不像看起来那么好。我们看到实现这样的“绑定引用”需要我们将原始方法包装在一个匿名函数中,这意味着调用绑定方法引用会导致两个方法调用:我们的匿名包装器和原始方法。如果几乎所有语言都有一件事,那就是方法调用的成本很高。
在这种情况下,我们可以在定义和调用错误函数(我们作为参数传递给每个函数的匿名方法)的同一代码位置访问原始的、所需的 this 关键字。我们可以简单地将正确的 this 引用保存在一个局部变量中,并在我们的迭代函数中使用它:
// ...
processItems: function() {
var that = this;
this.items.each(function(item) {
// Process item
that.markItemAsProcessed(item);
});
},
// ...
外卖点
回顾一下:
Any member access must be qualified with the object it pertains to, even when it is this.
Any sort of function reference (assigning as a value, passing as an argument) loses the function’s original binding.
JavaScript provides two equivalent ways of explicitly specifying a function’s binding when calling it: apply and call.
Creating a “bound method reference” requires an anonymous wrapper function, and a calling cost. In specific situations, leveraging closures may be a better alternative.
希望这可以帮助。