- jQueryのイベントオブジェクトは「偽物」なのか
- ネイティブイベントとは何か
- jQuery.Eventとは何をしているのか
- なぜラップする必要があったのか
- preventDefault と stopPropagation が動く理由
- ありがちなトラブル:nativeEventが必要になる瞬間
- なぜ混乱が起きやすいのか
- 実際に起きる問題
- jQueryの役割を正しく理解する
- 結局何が違うのか
jQueryのイベントオブジェクトは「偽物」なのか
jQueryのクリックイベントで受け取る引数eは、ブラウザのEventと同じものに見えます。しかし実際には同じではありません。結論から言うと、jQueryのイベントオブジェクトはネイティブイベントそのものではなく、ネイティブイベントを包んだラッパー(jQuery.Event)です。
この違いを知らないと、「なぜかプロパティが存在しない」「ブラウザごとに挙動が違う」といった混乱が起きます。逆にここを理解すると、jQueryがなぜ当時爆発的に普及したのかも見えてきます。
ネイティブイベントとは何か
まずブラウザの標準イベントです。addEventListenerで受け取るものがそれです。
document.getElementById('btn') .addEventListener('click', function(e){ console.log(e instanceof Event); // true });
このeはブラウザが生成したEventオブジェクトです。問題は、かつてのブラウザはこれが統一されていませんでした。
- IE:window.event
- Firefox:引数で渡される
- プロパティ名も異なる(srcElement / target)
つまり「クリックイベントを書く」だけで、ブラウザごとにコードを書き分ける必要がありました。
jQuery.Eventとは何をしているのか
jQueryはこの差異を吸収するため、イベントを独自オブジェクトに変換しています。
$('#btn').on('click', function(e){ console.log(e.constructor.name); // jQuery.Event });
ここで受け取っているのはネイティブのEventではありません。jQuery.Eventです。
ただし中身が全く別物というわけではありません。内部にネイティブイベントが保持されています。
$('#btn').on('click', function(e){ console.log(e.originalEvent); });
originalEventが、ブラウザの本物のイベントです。jQueryはそれを加工して、常に同じインターフェースで使えるようにしています。
なぜラップする必要があったのか
当時の最大の問題はプロパティの不統一でした。
| ブラウザ | クリックされた要素 |
| IE | srcElement |
| 標準 | target |
jQueryはこれを統一しました。
$('#btn').on('click', function(e){ console.log(e.target); // 常に同じ });
つまりjQueryは新機能を提供したのではなく、ブラウザの違いを無かったことにするための層です。
preventDefault と stopPropagation が動く理由
ネイティブイベントでは次のように書きます。
e.preventDefault(); e.stopPropagation();
jQueryでも同じコードが使えます。これはjQuery.Eventが内部でoriginalEventを呼び出しているためです。もし古いブラウザでpreventDefaultが存在しない場合でも、jQueryが代替処理を行います。
つまりjQueryのイベントオブジェクトは「便利」なのではなく、互換性を保証するためのアダプターです。
ありがちなトラブル:nativeEventが必要になる瞬間
普段はjQuery.Eventで十分ですが、例外があります。マウス座標や詳細なポインタイベントを扱う場合です。
$('#btn').on('click', function(e){ console.log(e.pageX); });
多くは問題ありませんが、ブラウザ固有の情報を扱うと値が期待と違う場合があります。そのときにoriginalEventを参照します。
e.originalEvent.clientX
ここで初めて「本物のイベント」を直接扱います。
なぜ混乱が起きやすいのか
理由は見た目が同じだからです。
- e.target が使える
- preventDefault も使える
- stopPropagation も使える
つまりネイティブEventと区別できません。しかし内部は別物です。このため、ネイティブAPIのドキュメント通りに書いたコードが動かないケースが発生します。
特にaddEventListenerへそのまま渡すと問題が起きます。
実際に起きる問題
次のようなコードです。
element.addEventListener('click', handler); $('#btn').on('click', handler);
同じhandlerでも、受け取るイベントの型が変わります。
- addEventListener → Event
- jQuery.on → jQuery.Event
この違いが原因で、型チェックやinstanceofが失敗します。
jQueryの役割を正しく理解する
jQueryのイベントオブジェクトは、DOMイベントを置き換えたものではありません。DOMイベントを安全に扱うための翻訳層です。
当時はこれが非常に重要でした。ブラウザごとの差異が大きく、イベント処理だけで大量の分岐が必要だったためです。
現在はブラウザが統一され、ラッパーの必要性は小さくなりました。しかし古いコードを読む場合や、イベントの挙動を理解する際には重要な知識です。
結局何が違うのか
違いをまとめると次の通りです。
- ネイティブイベント:ブラウザが生成
- jQuery.Event:互換性のためのラッパー
- originalEvent:本体
つまりjQueryのイベントは「別物」ではなく「加工済み」です。ここを理解していると、イベント周りの不具合の原因がかなり絞り込めるようになります。
jQueryはイベント処理を簡単にしたのではなく、壊れないようにしたライブラリだったと言えます。