"This" 在 es6 class 方法中

"This" within es6 class method

出于某种原因,我在 es6 class...

中得到了 "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 的点击方法中的 "this" 是指 dom 节点而不是...本身?

更重要的是,如果我不能使用 "this" 来执行此操作,如何从其点击方法中引用点击器的计数 属性?

Why is the "this" inside of of the Clickers' click method referring to the dom node rather than ... itself?

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


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

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

解释:

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

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

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

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

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 description of the six ways that this is set 很有用。


其他选项

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

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

或者在 ES6 中,箭头函数:

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

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