web-dev-qa-db-ja.com

ES6クラス:「addEventListener」がメソッドに適用された「this」へのアクセス

このes6スクリプトでは、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);
  }
}
40
Yukulélé

これは一般的な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? */);

添付した関数への参照はもうないので、イベントハンドラーを削除する方法はありません。

2つのオプションをお勧めします。

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