如何在回调中访问正确的“this”

2023-11-25

我有一个注册事件处理程序的构造函数:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

但是,我无法访问data回调中创建的对象的属性。看起来像this不是指已创建的对象,而是指另一个对象。

我还尝试使用对象方法而不是匿名函数:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

但它也存在同样的问题。

如何访问正确的对象?


你应该了解什么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();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在回调中访问正确的“this” 的相关文章

随机推荐