- C++ や Java 星人にとって JavaScript の
this
は混乱しまくるのだが、それを理解できるまでにお世話になったサイト
最初さっぱり意味がわからんくて困惑
JavaScript の勉強したての頃にこんなコードを書いて、大層困惑したのですよ。
class MyClass
{
private mouseCount: number = 0;
constructor()
{
// イベントリスナーとして自分のメソッドを渡す
document.addEventListener( 'mousedown', this.onMouseDown );
}
onMouseDown(
e: MouseEvent)
{
// この this は当然自分の事と思いきや、違う
// この例の場合だと、this は document を指してる
this.mouseCount++;
}
}
まあよく考えれば、addEventListener
に渡した物は単なる関数なので、確かにこのコードだけでは this
が紐づいてなさそうな雰囲気は察したのだけど、エラーにもならず onMouseDown
はちゃんと呼ばれて、でも this
が document
ってのがさっぱり意味が分からない。
で、「JavaScript this」 とかで調べると、まーみんな苦労したのか山ほど解説が見つかるのだけれど、以下でやっとしっくりきた。
JavaScript において this
ってのは関数の持ち主の事なので、イベントリスナーは登録先(今回の場合は document)が保持して呼んでる以上、関数内の this
はそのオブジェクトになる、と?
いやよく読むともっと面倒な事になってる気もするけど、まあなんにしろイベントリスナー内で this
をそのまま使っちゃいけないという事は分かった。
で、どうすりゃいいのよ
んでじゃあ、皆どうやって this
を渡してるのかと調べてみると、昔は、
// this を一度ローカル変数に渡して、それを無名関数に渡す
var self = this;
document.addEventListener( 'mousedown',
function(e) {
self.なんやらかんやら;
});
とかいろいろ工夫してなんとかしてたらしいですが、最近制定された アロー関数(C#のラムダ式と同じ記法)で記述した場合は、関数内の this
は関数定義した場所と同じ this
を指す という事になったらしい。単なる function()
の略記法かと思ってたら、超有能な子だった。
てことで、アロー関数を使って最初の例を書き換えると以下になりますね。結局どうやってもクラスメソッドをそのままイベントリスナーにはできないみたいだけど、まあこれならいいか。むしろ下手にメソッドにするよりその場で書けって事ですね。
document.addEventListener( 'mousedown', (e) => { this.onMouseDown(e); } );
なお、アロー関数はES6機能なので、IE は 11 でも使えないみたいですが、僕は最初から TypeScript 経由でしか JavaScript を使う気がないので、気にせず使いますよ。コンパイル結果を見てみたら、上の self
を使った例みたいに展開されてました。