クイズ: addEventListener()
に渡される 3 番目のパラメータの目的は何ですか。
addEventListener()
が 2 つのパラメータしか取っていない、またはバブルと関係があるとあいまいに理解しながら false
の値をハードコードしているなどと思われても当然です。
構成可能な addEventListener()
addEventListener()
メソッドは、ウェブの初期から大きな進歩を遂げ、その新機能は、3 つ目のパラメータの強化されたバージョンを介して構成されます。メソッドの定義に対する最近の変更により、デベロッパーは、構成オブジェクトを介して追加のオプションを提供できるようになりました。また、ブール値パラメータがある場合やオプションが指定されていない場合は、下位互換性を維持できます。
Chrome 55 では、passive
(Chrome 51 で実装)および capture
オプション(Chrome 49 で実装)とともに、この設定オブジェクトに once
オプションのサポートが追加されました。次に例を示します。
element.addEventListener('click', myClickHandler, {
once: true,
passive: true,
capture: true
});
これらのオプションは、ユースケースに合わせて必要に応じて組み合わせることができます。
大掃除をするメリット
以上が新しい once
オプションを使用するための構文ですが、これで何ができるのでしょうか?つまり、「1 回で完了」のユースケースに合わせたイベント リスナーが用意されています。
デフォルトでは、イベント リスナーは初回呼び出された後も保持されます。これは、一部のイベント(複数回クリック可能なボタンなど)では望ましいことです。ただし、他の用途では、イベント リスナーを用意する必要はありません。1 回だけ実行する必要があるコールバックがある場合は、望ましくない動作につながる可能性があります。健全なデベロッパーであれば、これまでも次のようなパターンで removeEventListener()
を使用して明示的にクリーンアップしていました。
element.addEventListener('click', function cb(event) {
// ...one-time handling of the click event...
event.currentTarget.removeEventListener(event.type, cb);
});
新しい once
パラメータを使用した同等のコードはより簡潔で、イベントの名前(上記の例の event.type
)やコールバック関数(cb
)への参照を追跡する必要はありません。
element.addEventListener('click', function(event) {
// ...one-time handling of the click event...
}, {once: true});
また、イベント ハンドラをクリーンアップすると、コールバック関数に関連付けられたスコープを破棄し、そのスコープでキャプチャされた変数のガベージ コレクションを行えるようにすることで、メモリの効率を向上させることもできます。違いを生む例を次に示します。
function setUpListeners() {
var data = ['one', 'two', '...etc.'];
window.addEventListener('load', function() {
doSomethingWithSomeData(data);
// data is now part of the callback's scope.
});
}
デフォルトでは、load
イベント リスナー コールバックは、一度も使用されていなくても、実行が完了したらスコープ内に残ります。data
変数はコールバック内で使用されるため、スコープ内に留まり、ガベージ コレクションは行われません。ただし、once
パラメータを介してコールバックが削除された場合は、関数自体と、そのスコープを介して保持されているものの両方がガベージ コレクションの対象になる可能性があります。
ブラウザ サポート
Chrome 55 以降、Firefox 50 以降、Safari のテクノロジー プレビュー 7 以降では、once
オプションがネイティブにサポートされています。
JavaScript UI ライブラリの多くは、イベント リスナーを作成するための便利なメソッドを備えています。また、1 回限りのイベントを定義するショートカット(最も注目すべき jQuery の one()
メソッド)を備えたライブラリもあります。ポリフィルも、Andrea Giammarchi の dom4
ライブラリの一部として使用できます。
ありがとう
この投稿のサンプルコードに関するフィードバックをお寄せいただいた Ingvar Stepanyan に感謝いたします。