JavaScriptのクラス内でのアロー関数(thisの固定)の動作について理解しよう
JavaScriptのクラス内でのアロー関数(thisの固定)の動作について
JavaScriptにおいて、this
が参照するものは実行箇所によって異なります。
アロー関数を使うと、this
の実行箇所に関わらず参照先は変わらないので、コードが読みやすくなります。
アロー関数とthisの話はクラスに限った話ではありませんが、悩むことが多い概念なので、クラス構文における「this」の使い方としてまとめておきます。
構文
構文 | 意味 |
---|---|
() => {} | アロー関数を定義する |
サンプルコード
サンプルコードとして、クリック回数を計測するコードを紹介します。
NGコード
まずはNGコードを紹介します。
NG例 |
---|
table.table
tbody
tr
th NG例
td#targetTextNG
button.btn.brandia_btn#targetButtonNG カウントボタン
<table class="table">
<tbody>
<tr>
<th>NG例</th>
<td id="targetTextNG"></td>
</tr>
</tbody>
</table>
<button class="btn brandia_btn" id="targetButtonNG">カウントボタン</button>
const targetTextNG = document.getElementById( 'targetTextNG' );
const targetButtonNG = document.getElementById( 'targetButtonNG' );
//NGコード
class TargetLikeCounterNG {
constructor() {
// ボタンをクリックした数
this.clickedCount = 0;
const targetTextNG = document.getElementById( 'targetTextNG' );
targetButtonNG.addEventListener('click', function() {
this.clickedCount += 1;
targetTextNG.textContent = this.clickedCount;
});
}
}
new TargetLikeCounterNG();
このコードはNGです。何故でしょうか?イベントリスナーの知識をきちんと持っていないと皆目検討もつかないでしょう。
イベントリスナー内のthisが参照するものはそのイベントターゲットになります。
つまり、上記のコードではthis.clickedCount
はTargetTextCounter
のクラス変数を参照せず、イベントリスナーのthisを参照しようとします。
この場合はイベントリスナーで参照されるのはButton要素です。Buttonの属性にclickedCount
はありませんから、上記のコードの様にButton属性のclickedCount
に代入しようとしても弾かれます。
というわけで、ボタンを何回押しても「NaN」が返ります。
正しいコード
ただし、次の様にイベントリスナー部分をアロー関数に書き換えることで、プログラムは正しく動作します。
正しい例 |
---|
table.table
tbody
tr
th 正しい例
td#targetText
button.btn.brandia_btn#targetButton カウントボタン
<table class="table">
<tbody>
<tr>
<th>正しい例</th>
<td id="targetText"></td>
</tr>
</tbody>
</table>
<button class="btn brandia_btn" id="targetButton">カウントボタン</button>
const targetText = document.getElementById( 'targetText' );
const targetButton = document.getElementById( 'targetButton' );
//コード
class TargetLikeCounter {
constructor() {
// ボタンをクリックした数
this.clickedCount = 0;
const targetText = document.getElementById( 'targetText' );
targetButton.addEventListener('click', () => {
this.clickedCount += 1;
targetText.textContent = this.clickedCount;
});
}
}
new TargetLikeCounter();
アロー関数では、this
はアロー関数自身が定義された場所によって決まります。言い換えるなら、アロー関数は「イベントリスナー内であってもアロー関数自身が宣言された場所」によって決まります。
そのため、上記のコードではクラス内でアロー関数が定義されているのですから、この場合のthis
はクラスになります。
結果、このthis
はクラスのクラス変数「this.clickedCount
」の「this
」を正しく参照しますから、カウント計測ボタンは期待通りの動作をします。
この様にthis
の扱いは要注意です。イベントリスナーのイベントターゲットを明示的に示す必要がある場合をのぞき、アロー関数の使用を統一した方がバグに悩まされることが少ないでしょう。