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はイベント処理を簡単にしたのではなく、壊れないようにしたライブラリだったと言えます。