Подтвердить что ты не робот

Класс ES6: доступ к 'this' с помощью 'addEventListener', применяемого к методу

В этом сценарии 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);
  }
}
4b9b3361

Ответ 1

Это общая проблема JS, но суть ее в том, что

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

не отличается от

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

Вы передаете функцию в качестве обработчика событий, но не гарантировали, что при вызове fn значение this будет установлено в нужное значение. Самый простой способ сделать это в ES5 -

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

или в ES6, используя функцию стрелки:

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

Обратите внимание, однако, что оба этих решения сломают вашу (уже слегка сломанную) логику в kill, потому что

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

У вас больше нет ссылки на связанную с вами функцию, поэтому у вас нет способа удалить обработчик событий.

Я бы предложил два варианта:

// 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);

или

// 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);