ES6类:在方法上应用'addEventListener'访问'this'

Yuk*_*élé 40 javascript dom dom-events ecmascript-6

在这个es6脚本中,click事件不起作用,因为sayHello方法是用this.elm(<div>)调用的this.

如何在不松散范围的情况下将事件与方法相关联?

class player{
  constructor (name) {
    this.name = name;
    this.elm = document.createElement('div');
    this.elm.addEventListener('click', this.sayHello);
  }
  sayHello() {
    console.log(this.name + ' say: "hello!"'); // 'undefined say 'hello!"';
  }
  kill() {
    console.log(`RIP ${this.name} :'(`); 
    this.elm.addClass('dead');
    this.elm.removeEventListener('click', this.sayHello);
  }
}
Run Code Online (Sandbox Code Playgroud)

log*_*yth 97

这是一个普遍的JS问题,但它的核心是

this.elm.addEventListener('click', this.sayHello);
Run Code Online (Sandbox Code Playgroud)

没有什么不同

var fn = this.sayHello;
this.elm.addEventListener('click', fn);
Run Code Online (Sandbox Code Playgroud)

您正在将函数作为事件处理程序传递,但尚未确保在fn调用时this将其设置为所需的值.在ES5中执行此操作的最简单方法是

this.elm.addEventListener('click', this.sayHello.bind(this));
Run Code Online (Sandbox Code Playgroud)

或者在ES6中,使用箭头功能:

this.elm.addEventListener('click', evt => this.sayHello(evt));
Run Code Online (Sandbox Code Playgroud)

但请注意,这两种解决方案都会破坏你的(已经略微破碎)逻辑kill因为

this.elm.removeEventListener('click', /* what? */);
Run Code Online (Sandbox Code Playgroud)

您没有任何对您附加的函数的引用,因此您无法删除事件处理程序.

我建议两个选择:

// Create a new function that is bound, and give it a new name
// so that the 'this.sayHello()' call still works.
this.boundSayHello = evt => this.sayHello(evt);
this.elm.addEventListener('click', this.boundSayHello);
this.elm.removeEventListener('click', this.boundSayHello);
Run Code Online (Sandbox Code Playgroud)

要么

// Bind the function with the same name and use `.bind` instead of the
// arrow function option.
this.sayHello = this.sayHello.bind(this);
this.elm.addEventListener('click', this.sayHello);
this.elm.removeEventListener('click', this.sayHello);
Run Code Online (Sandbox Code Playgroud)