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

函数MyConstructor(数据,传输){this.data=数据;transport.on('数据',函数(){警报(this.data);});}//模拟传输对象var传输={on:函数(事件,回调){setTimeout(回调,1000);}};//称为var obj=新MyConstructor('o',传输);

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

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

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

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

但它表现出相同的问题。

如何访问正确的对象?


当前回答

另一种方法是EventListener接口中的handleEvent(evt)方法,这是自DOM2以来将其绑定到事件侦听器中的标准方法,它允许您始终删除侦听器(以及其他好处):

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

有关使用handleEvent的详细信息可以在以下位置找到:DOM handleEvent:自2000年以来的跨平台标准

其他回答

问题围绕着this关键字在JavaScript中的行为。这表现如下不同,

其值通常由函数执行上下文确定。在全局范围中,这是指全局对象(窗口对象)。如果为任何函数启用了严格模式,则其值将是未定义的,因为在严格模式中,全局对象是指未定义的窗口对象。位于点之前的对象是this关键字将绑定到的对象。我们可以使用call()、bind()和apply()显式设置此值当使用new关键字(构造函数)时,它将绑定到正在创建的新对象。箭头函数不绑定此 — 相反,这是在词汇上绑定的(即,基于原始上下文)

正如大多数答案所建议的那样,我们可以使用arrow函数或bind()方法或Self var。我将引用GoogleJavaScript风格指南中关于lambdas(arrow函数)的一点

更喜欢使用箭头函数而不是f.bind(this),尤其是在goog.绑定(f,this)。避免写入常量self=this。箭头功能对于有时意外传递的回调特别有用其他参数。

谷歌明确建议使用lambdas,而不是bind或const self=this

因此,最好的解决方案是使用如下lambdas,

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

参考文献:

https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c箭头函数与绑定

以下是访问子上下文中的父上下文的几种方法-

您可以使用bind()函数。在另一个变量中存储对context/this的引用(参见下面的示例)。使用ES6箭头功能。改变代码、功能设计和架构——为此,您应该能够控制JavaScript中的设计模式。

1.使用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);

如果您正在使用Undercore.js-http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2.在另一个变量中存储对context/this的引用

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

3.箭头功能

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

其他一些人已经谈到了如何使用.bind()方法,但这里特别介绍了如果有人在让它们一起工作时遇到困难,如何将其与.then()一起使用:

someFunction()
.then(function(response) {
    //'this' wasn't accessible here before but now it is
}.bind(this))

如注释中所述,另一种方法是使用没有自己的“this”值的箭头函数

someFunction()
.then((response)=>{
    //'this' was always accessible here
})

“上下文”的问题

术语“上下文”有时用于指代此引用的对象。它的使用是不合适的,因为它在语义上或技术上都不符合ECMAScript的this。

“上下文”是指围绕着某事物的环境,它增加了意义,或是一些前后信息赋予了额外的意义。ECMAScript中使用术语“上下文”来指代执行上下文,它是一些执行代码范围内的所有参数、范围和内容。

如ECMA-262第10.4.2节所示:

将ThisBinding设置为与调用执行上下文

这清楚地表明这是执行上下文的一部分。

执行上下文提供为正在执行的代码添加意义的周围信息。它包含了比thisBinding更多的信息。

它的价值不是“上下文”。它只是执行上下文的一部分。它本质上是一个局部变量,可以通过对任何对象的调用,在严格模式下,设置为任何值。

我们不能将其绑定到setTimeout(),因为它总是使用全局对象(Window)执行。如果您想在回调函数中访问this上下文,那么通过对回调函数使用bind(),我们可以如下实现:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);