はじめに
JavaScriptでイベント処理を実装する際、addEventListenerメソッドは欠かせない存在です。しかし、このメソッド内でのthisの挙動は初学者にとって混乱しやすいポイントの一つです。
本記事では、addEventListenerにおけるthisの挙動について、具体例を交えながら解説していきます。
addEventListenerでのthisの基本
addEventListenerにイベントハンドラとして通常の関数を渡した場合、関数内のthisはイベントが発生した要素(イベントターゲット)を参照します。
const button = document.querySelector('#myButton');
button.addEventListener('click', function() {
console.log(this); // <button id="myButton">が出力される
console.log(this === button); // true
});
この挙動は、イベントハンドラ内で対象要素のプロパティやメソッドに直接アクセスできるため便利です。
通常の関数とアロー関数での違い
thisの挙動は、使用する関数の種類によって大きく異なります。
通常の関数の場合
通常の関数では、thisはイベントが発生した要素を指します。
const button = document.querySelector('#myButton');
button.addEventListener('click', function() {
console.log(this); // buttonを参照
this.textContent = 'クリックされました'; // 要素のテキストを変更できる
});
アロー関数の場合
アロー関数では、thisは定義された時点でのスコープのthisを継承します。イベントターゲットを参照しません。
const button = document.querySelector('#myButton');
button.addEventListener('click', () => {
console.log(this); // windowオブジェクトまたは外側のスコープのthisを参照
// this.textContent = '...' とすると期待通りに動作しない
});
以下の図で、それぞれのthisがどこを参照するかを視覚化してみましょう。
実際の使用例
パターン1: 要素自身を操作したい場合
要素自身のスタイルやテキストを変更したい場合は、通常の関数が適しています。
const buttons = document.querySelectorAll('.toggle-button');
buttons.forEach(button => {
button.addEventListener('click', function() {
// thisで直接要素にアクセス
this.classList.toggle('active');
this.textContent = this.classList.contains('active')
? 'ON'
: 'OFF';
});
});
パターン2: 外側のスコープにアクセスしたい場合
クラスのメソッドやオブジェクトのプロパティにアクセスしたい場合は、アロー関数が便利です。
class Counter {
constructor() {
this.count = 0;
this.button = document.querySelector('#countButton');
this.display = document.querySelector('#countDisplay');
// アロー関数で外側のthis(Counterインスタンス)を参照
this.button.addEventListener('click', () => {
this.count++; // Counterインスタンスのcountにアクセス
this.display.textContent = this.count;
});
}
}
const counter = new Counter();
パターン3: 両方必要な場合
イベントターゲットと外側のスコープの両方が必要な場合は、イベントオブジェクトのcurrentTargetプロパティを使用します。
class ButtonManager {
constructor() {
this.clickCount = 0;
document.querySelectorAll('.button').forEach(button => {
button.addEventListener('click', (event) => {
this.clickCount++; // 外側のthis(ButtonManagerインスタンス)
const clickedButton = event.currentTarget; // イベントターゲット
clickedButton.textContent = `クリック数: ${this.clickCount}`;
});
});
}
}
以下の図で、各パターンの使い分けを整理してみましょう。
まとめ
addEventListenerにおけるthisの挙動は、使用する関数の種類によって変わります。
-
通常の関数:
thisはイベントターゲット要素を参照 -
アロー関数:
thisは外側のスコープのthisを参照
どちらを使うかは、実装したい処理によって使い分けましょう。要素自身を操作したい場合は通常の関数、外側のスコープにアクセスしたい場合はアロー関数が適しています。
この仕組みを理解しておくことで、イベント処理の実装がよりスムーズになりますね。