JavaScriptのイベントリスナーに関数を渡す際に初心者が犯しがちな間違い

addEventListener メソッドは JavaScript を使って HTML に動きを持たせようとしたときに最も良く使用されるメソッドの一つです。
そんな addEventListener メソッドですが、初心者が躓きやすいポイントが幾つかあります。この記事ではそれらの躓きやすい点についてまとめようと思います。

1. 引数に()を付けてしまう

以下のコードは hello ボタンを押すとコンソールに hello と表示させようとして失敗しているコードです。

<body>
    <button id="btn">hello</button>
    <script>
        const btn = document.getElementById("btn");

        // 関数定義
        function hello() {
            console.log("hello");
        }

        // ボタンにイベントを追加する
        btn.addEventListener("click", hello());
    </script>
</body>

このコードを実行するとページのロードと共にイベントリスナーの関数 hello が実行されます。また、ボタンを押してもコンソールに hello が追加されることはありません。
この処理の問題点は関数 hello がイベントリスナーの追加と共に実行されてしまっていることです。
hello はイベントリスナーの追加時に一度だけ実行されイベント発火時には呼び出されません。

改善する方法は以下の通りです。

<body>
    <button id="btn">hello</button>
    <script>
        const btn = document.getElementById("btn");

        // 関数定義
        function hello() {
            console.log("hello");
        }

        // 1. ()を付けない
        btn.addEventListener("click", hello);

        // 2. アロー関数でラップする
        btn.addEventListener("click", () => hello());

        // 3. 無名関数でラップする
        btn.addEventListener("click", function() { hello() });
    </script>
</body>

上記いずれかの方法を用いることで想定通りの挙動を実装することができます。

無名関数やアロー関数を使った場合

先ほどアロー関数や無名関数を使って実行したい処理をラップする方法を紹介しましたが、それらの方法で設定したイベントリスナーは削除することが難しいです。 ですので、もしつかしたイベントリスナーを削除する予定がある場合はそれらの方法は避けた方が良いでしょう。

既に設定されているイベントを削除するためには removeEventListener メソッドを使います。このメソッドでは下記の通り削除したいイベント型とイベントリスナー関数を指定する必要があります。

btn.removeEventListener('click', hello);

無名関数やアロー関数はそのままでは使いまわしができない関数です。ですので removeEventListener の引数に指定することはできません。上記のようにアロー関数や無名関数の中で実行されている関数を指定しても、それらの関数はイベントリスナー関数ではないので削除することは出来ません。

削除する予定のあるイベントリスナーの設定は上記3つの方法の内 1番目の方法で行う必要があります。

<body>
    <!-- hello ボタン -->
    <button id="btn">hello</button>
    <!-- remove ボタン -->
    <button id="remove">remove</button>
    <script>
        const btn = document.getElementById("btn");
        const removeBtn = document.getElementById("remove");

        function hello() {
            console.log("hello");
        }

        // イベント設定
        btn.addEventListener("click", hello);

        // イベントを消去する関数
        function removeEvent() {
            btn.removeEventListener('click', hello);
        }

        // removeボタンでhelloイベントを削除
        removeBtn.addEventListener('click', removeEvent);
    </script>
</body>

このコードではhelloボタンのクリックでコンソールにhelloと表示されremoveボタンを押すとhelloボタンのイベントリスナーが削除されhelloが追加されなくなります。