es6类方法中的“this”

IT技术 javascript class ecmascript-6 this
2021-01-31 09:23:00

出于某种原因,我在 es6 类中为“this”获得了奇怪的值...

'use strict';
class Clicker {
  constructor(element) {
    this.count = 0;
    this.elem = element;
    this.elem.addEventListener('click', this.click);
    
    // logs Clicker { count:0, elem: button#thing} as expected
    console.log(this);
  }

  click() {
    // logs <button id="thing">...</button> as unexpected...
    console.log(this);
    this.count++;
  }
}


var thing = document.getElementById('thing');
var instance = new Clicker(thing);
<button id="thing">Click me</button>

问题:

为什么 Clickers 的 click 方法中的“this”指的是 dom 节点而不是 ... 本身?

更重要的是,如果我不能使用“this”来做到这一点,我如何从它的“click”方法中引用 Clickers 的 count 属性?

1个回答

为什么 Clickers 的 click 方法中的“this”指的是 dom 节点而不是 ... 本身?

因为规范.addEventListener()是设置this指向捕获事件的DOM元素指针。这就是它的工作原理。


当将方法作为回调传递给您想要覆盖 的值时this,您可以使用它.bind()来强制所需的值this

this.elem.addEventListener('click', this.click.bind(this));

解释:

Javascript 中的所有函数调用都会this根据函数的调用方式设置一个新值有关基本规则集的更多信息,请参阅此说明

最重要的是,当你这样做时:

this.elem.addEventListener('click', this.click);

您只是获取this.click方法并将该方法单独传递给addEventListener(). 的valuethis将完全丧失。就好像你在这样做:

var m = this.click;     // m here is just a reference to Clicker.prototype.click
this.elem.addEventListener('click', m);

最重要的是,.addEventListener()它专门用于this在调用回调时设置它自己的值(指向this创建事件的元素)。

因此,您可以使用.bind()如上所示this的方法在调用您的方法时强制使用适当的值


作为参考,您可能会发现在 Javascript 中为函数调用设置的六种方式的描述this很有用。


其他选项

我发现.bind()这是定义它的最清晰的方法,但您也可以使用本地匿名函数:

var self = this;
this.elem.addEventListener('click', function() {
    self.click();
});

或者在 ES6 中,一个箭头函数:

this.elem.addEventListener('click', () => this.click());

箭头函数将this自动为您保留 的值,以避免需要self前面示例中使用引用。

@AndrewLuhring - 注意,我添加了更多解释。
2021-03-19 09:23:00
似乎这种this.elem.addEventListener('click', this.click.bind(this));语法不允许我们删除侦听器,就像它是另一个函数一样。但我真的不明白。有人向我解释为什么它的行为如此?
2021-03-19 09:23:00
@sniels - 我在答案中添加了您的选项和另一个选项。好主意。
2021-03-23 09:23:00
我知道这很简单。预计您的解决方案会在大约 12 分钟内被接受。
2021-03-27 09:23:00
除了这个答案之外,您还可以使用this.elem.addEventListener('click', () => this.click());我相信来解决它
2021-04-04 09:23:00