jQueryでbindとliveとdelegateの使い分け

ふと整理しておこうと思ったのでメモ。
1.7で各メソッドはon/offの委譲として実装されるようになったが、これをちゃんと理解してないと非効率なイベント設定をすることになってしまう。

イベントが登録される要素

bindとdelegateはセレクタで指定された要素。liveはdocument。

$('#foo').bind('click', fn); // #foo
$('#foo').delegate('#bar', 'click', fn); // #foo
$(document).delegate('#bar', 'click', fn); // document
$('#foo').live('click', fn); // document

bindが動的に追加された要素に適用できないのはイベントを登録する要素がないから。
liveが同じような書き方なのにできるのは、$('#foo')で検索された要素を使用せず、contextにイベントハンドラを登録しているから。その代償として$('#foo')で余計な検索を一度行なってしまっている。

$('#foo').context === document // true

また、bindは要素に対してイベントを登録するため、セレクタにマッチする要素が多いとイベント登録処理に時間がかかり、メモリ効率も悪い。

実行順序

<div id="outer">
  <div id="inner">
    hello
  </div>
</div>

といったHTMLで#innerに対するクリックイベントを書こうとすると以下のようになる。

$('#inner').bind('click', fn); // A
$('#outer').delegate('#inner', 'click', fn); // B
$(document).delegate('#inner', 'click', fn); // C
$('#inner').live('click', fn); // D

#innerをクリックすると、

#inner.click → #outer.click → document.click

の順でイベントが発生するので、実行順序は

A → B → C ≒ D

になる。

まぁ、大差ないだろうけど。

あれ?んじゃ、delegateだけでよくね?

delegateだとchainを書きにくいんだよね。。

$('#foo a').bind('click', fn).show(); // スッキリ
$('#foo').delegate('a', 'click', fn);
$('#foo a').show(); // モヤット

俺的まとめ

  • 基本、bindで。書きやすいしチェーンもしやすい。スコープが小さいのもいいことだ。
  • bindする対象が多い or DOM追加した時にbindをつけるのがめんどくさそうだったらdelegate。
  • liveはいらない子。

liveが$(selector).live()じゃなくて、$.live(selector)だったらよかったのにねぇ。
$(document).on('click', '#foo a', fn)って書き方もちょっと冗長。