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

132 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-Debug实录任务,点击查看活动详情

问题描述:

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

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);
};

但它表现出同样的问题。 如何访问正确的对象?

解决方法:

  • 使用bind()功能
function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

如果使用的是 Underscore.js - underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));
  • 在另一个变量中存储对 context/this 的引用
function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}
  • 使用箭头函数
function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

总结:

与其他语言相比,函数的this关键字在 JavaScript 中的行为略有不同。

严格模式和非严格模式也有一些区别。

在大多数情况下, this 的值取决于函数的调用方式。

执行时不能通过赋值来设置,每次调用函数时可能都不一样。

ES5 引入了 bind() 方法来设置函数的值,this而不管它是如何被调用的,

并且 ES2015 引入了不提供this绑定的箭头函数(它保留了封闭词法上下文的这个值)。