你应该了解什么this
this
(又名“上下文”)是每个函数内的特殊关键字,其值仅取决于how函数被调用,而不是它是如何/何时/在哪里定义的。它不像其他变量一样受到词法作用域的影响(箭头函数除外,见下文)。这里有些例子:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
要了解更多信息this
,看看MDN 文档.
如何参考正确的this
Use 箭头函数
ECMAScript 6 推出箭头函数,可以将其视为 lambda 函数。他们没有自己的this
捆绑。反而,this
就像普通变量一样在范围内查找。这意味着您不必打电话.bind
。这并不是他们唯一的特殊行为,请参阅 MDN 文档以获取更多信息。
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
不要使用this
您实际上不想访问this
特别是,但是它所指的对象。这就是为什么一个简单的解决方案是简单地创建一个也引用该对象的新变量。变量可以有任何名称,但常见的是self
and that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Since self
是一个普通变量,它遵循词法范围规则并且可以在回调内部访问。这还有一个优点,您可以访问this
回调本身的值。
显式设置this
回调 - 第 1 部分
您可能看起来无法控制其价值this
因为它的值是自动设置的,但实际上并非如此。
Every function has the method .bind [docs], which returns a new function with this
bound to a value. The function has exactly the same behavior as the one you called .bind
on, only that this
was set by you. No matter how or when that function is called, this
will always refer to the passed value.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
在这种情况下,我们绑定回调的this
的值MyConstructor
's this
.
Note: When a binding context for jQuery, use jQuery.proxy [docs] instead. The reason to do this is so that you don't need to store the reference to the function when unbinding an event callback. jQuery handles that internally.
Set this
回调 - 第 2 部分
Some functions/methods which accept callbacks also accept a value to which the callback's this
should refer to. This is basically the same as binding it yourself, but the function/method does it for you. Array#map [docs] is such a method. Its signature is:
array.map(callback[, thisArg])
第一个参数是回调,第二个参数是值this
应参考。这是一个人为的例子:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Note: Whether or not you can pass a value for this
is usually mentioned in the documentation of that function/method. For example, jQuery's $.ajax method [docs] describes an option called context
:
该对象将成为所有 Ajax 相关回调的上下文。
常见问题:使用对象方法作为回调/事件处理程序
此问题的另一个常见表现是当对象方法用作回调/事件处理程序时。函数是 JavaScript 中的一等公民,术语“方法”只是函数的通俗术语,函数是对象属性的值。但该函数没有与其“包含”对象的特定链接。
考虑以下示例:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
功能this.method
被指定为单击事件处理程序,但如果document.body
单击后,记录的值将是undefined
,因为在事件处理程序内部,this
指的是document.body
,不是实例Foo
.
正如一开始已经提到的,什么this
指的是取决于功能如何called,不是这样的defined.
如果代码如下所示,则该函数没有对该对象的隐式引用可能会更明显:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
解决方案与上面提到的相同:如果可用,请使用.bind
显式绑定this
到特定值
document.body.onclick = this.method.bind(this);
或者通过使用匿名函数作为回调/事件处理程序并分配对象来显式调用该函数作为对象的“方法”(this
) 到另一个变量:
var self = this;
document.body.onclick = function() {
self.method();
};
或使用箭头函数:
document.body.onclick = () => this.method();