こんにちは、つばさ(@tsubasa123)です。
先日の続き。アロー関数ってやっぱり便利で使えるときは積極的に使うようにしているのですが、まだまだthis
に悩まされておりまして。
もう少し詳細に把握しておきたかったので色々試した過程をメモしておきます。
thisは定義時に束縛される
まずはおさらいから。
const tsubasa = { name: 'tsubasa', hello: function() { setTimeout(() => { console.log('hello ' + this.name); }); }, }; tsubasa.hello(); // tsubasa
このように、setTimeout()
関数などに渡すコールバックをアロー関数で定義すると、関数内でのthis
はグローバルオブジェクトではなく、アロー関数を定義したコンテキストのthis
オブジェクトを参照するようになる。
先の例だとtsubasa
オブジェクトのhello
メソッド内でアロー関数が定義されているので、hello
メソッドが参照するthis
、つまりtsubasa
オブジェクトを参照するようになる、と。
「アロー関数を定義したコンテキストのthis」って言い回しに違和感を覚えますが、アロー関数を利用することでthis
がグローバルオブジェクトに置き換わってしまうJavaScriptの謎仕様から解放されるようになることがわかりました。
ここまでは大体把握していました。ここからは実際にアローを使って戸惑ったところをまとめていきます。
オブジェクトのメソッドにアロー関数を利用した時
先ほどのコードに似ていますが、このように指定するとエラーになります。
const tsubasa = { name: 'tsubasa', hello: () => { console.log('hello ' + this.name); // Cannot read property 'name' of undefined }, }; tsubasa.hello();
hello
メソッドの定義をアロー関数に変更すると、このようにエラーになります。アロー関数を定義する時のコンテキストのthis
はこの場合はtsubasa
ではなく、グローバルオブジェクトになってしまうのでプロパティが見つからずにエラーとなります。tsubasa
オブジェクトの定義時のthis
が束縛されることになるのかな。
アロー関数が使えるからといってむやみやたらにコードを書き替えるとこのようなエラーになることもありますので気をつけましょう。私はえらい目にあいました。
イベントハンドラにアロー関数を利用した時
今回はjQueryを利用してハマりましたが、本質的にはjQueryは関係なく、addEventListener
を利用しても同じことになると思います。id=hoge
の要素に何かテキストが入っていると仮定します。
$hoge.on('click', function(e) { console.log($(this).text()); // 要素の中のテキストが表示されます });
コールバックにアロー関数を使わない従来の指定方法だと、コールバック関数内のthis
にはイベントの対象となる要素、この場合はクリックされたDOM要素が参照されるので、上記のようにthis
を利用してクリック対象にアクセスすることができます。
$hoge.on('click', (e) => { console.log($(this).text()); // 何も表示されない });
対して、アロー関数を利用すると要素のテキストは表示されません。理由はもうおわかりですね。this
が参照するオブジェクトがクリックされたDOM要素ではなく、アロー関数を定義する時のコンテキストのthis
を参照するからです。
アロー関数をイベントハンドラで指定する際は、
$hoge.on('click', (e) => { console.log($(e.currentTarget).text()); // 要素の中のテキストが表示されます });
このように、イベントオブジェクトを経由してイベント対象の要素にアクセスする必要があります。
jQueryへのコールバックにアロー関数を利用した時
なんて名前をつければよいのかわからなかったのですが、コードを見てもらえればなんとなくニュアンスは伝わるかと思います。
$('#list li').each(function() { console.log($(this).text()); // 要素の中のテキストが表示されます });
jQueryで取得したDOM要素に対して何か処理を行いたいときは、each
メソッドなどを使ってコールバックを指定することができます。ここにも当然アロー関数は指定できます。
$hoge.on('click', (e) => { console.log($(this).text()); // 何も表示されない });
アロー関数をコールバックに利用すると、イベントハンドラの時と同じ結果になってしまいます。
$('#list li').each((k, v) => { console.log($(v).text()); });
アロー関数を利用したときは、コールバック関数の引数を利用して各要素にアクセスするようにします。このとき、引数は2つ渡されてきて2つ目に対象となる要素が格納されているので注意しましょう。1つ目と勘違いすると結構ハマったりします。
アロー関数マジ便利
const divRegion = { name: 'hogehoge', init: function() { $('#btn').on('click', (e) => { console.log(this.name); // hogehoge console.log($(e.currentTarget).text()); // 要素の中のテキストが表示されます }); }, }; divRegion.init();
当たり前ですが、併用すると捗ります。jQueryを使って、DOMベースでゴリゴリとイベント駆動させるならアロー関数じゃないほうがDOM要素にアクセスしやすいかもしれません。ですが、まぁ、管理は難しくなりますよね。
一長一短なところがあると思いますが、アロー関数のthis
の特性を把握すればコーディングは捗ること間違いない、と思いました。
さいごに
だいぶわかってきました、アロー関数。やはり新技術は導入していかないとダメですね、べんりべんり。機会があればトランスパイラ使ってブログのカスタマイズにも導入してみたいところです。
ではでは、最後までお付き合いいただきありがとうございました。
コメント