关于javascript:ES6类:在方法上应用’addEventListener’访问’this’

ES6 Class: access to 'this' with 'addEventListener' applied on method

本问题已经有最佳答案,请猛点这里访问。

在这个ES6脚本中,click事件不起作用,因为sayHello方法是用this.elm(作为this调用的。

如何将一个事件关联到一个方法而不释放作用域?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
  }
}

这是一个通用的JS问题,但其核心是

1
this.elm.addEventListener('click', this.sayHello);

1
2
var fn = this.sayHello;
this.elm.addEventListener('click', fn);

您正在传递一个函数作为事件处理程序,但没有确保当调用fn时,this将被设置为所需的值。在ES5中最简单的方法是

1
this.elm.addEventListener('click', this.sayHello.bind(this));

或在ES6中,使用箭头函数:

1
this.elm.addEventListener('click', evt => this.sayHello(evt));

但是请注意,这两个解决方案都会破坏您在kill中的逻辑(已经稍微破坏了),因为

1
this.elm.removeEventListener('click', /* what? */);

您不再具有对所附加函数的任何引用,因此无法删除事件处理程序。

我建议两种选择:

1
2
3
4
5
// 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);

1
2
3
4
5
// 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);