web-dev-qa-db-ja.com

es6クラスメソッド内の「これ」

何らかの理由で、es6クラスの "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>

質問:

なぜクリッカーのクリックメソッド内の「this」が...自体ではなくdomノードを参照するのですか?

さらに重要なのは、「this」を使用してクリックできない場合に、クリックメソッド内からクリッカーのカウントプロパティを参照するにはどうすればよいですか。

27
Andrew Luhring

なぜクリッカーのクリックメソッド内の「this」が...自体ではなくdomノードを参照するのですか?

.addEventListener()の仕様では、thisポインターをイベントをキャッチしたDOM要素に設定するためです。それが動作するように設計されている方法です。


thisの値をオーバーライドするコールバックとしてメソッドを渡す場合、.bind()を使用してthisの目的の値を強制できます。

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

説明:

JavaScriptのすべての関数呼び出しは、関数の呼び出し方法に応じてthisの新しい値を設定します。基本的なルールセットの詳細については、 この説明 を参照してください。

それに加えて、これを行うと:

_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が設定される6つの方法のこの説明 を見つけることができます。


その他のオプション

.bind()がこれを定義する最も明確な方法であると思いますが、ローカルの匿名関数を使用することもできます。

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

またはES6では、矢印関数:

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

前の例で使用したthis参照が不要になるように、矢印関数はselfの値を自動的に保存します。

30
jfriend00