使ってはいけないjQueryの機能 5個

3 days ago的な時間表記をするサービスは全部嫌いです。agoです。

週末若手IT勉強会に参加させていただきjQuery 1.3.2のイベント周りを読んできたので、それを踏まえて使用すると問題の発生する可能性の高い機能を紹介します。

0 jQuery.browser

1.3からサポート外になりました。

代わりにjQuery.supportを使用しましょう。

ただ、swfの重ね合わせ問題等は単体のJSでは確認できないので、jQuery.browser無しでどう解決すればいいのかよくわかっていません。

1 getData、setDataイベント

getData、setDataイベントは1.5系で削除される予定のようです

最新版のjQueryではgetData、setDataイベントが使用可能になっており、以下のようにイベントを設定できます。

$().bind('getData', function () {
    console.log('getData', this, arguments);
});
$().bind('setData', function () {
    console.log('setData', this, arguments);
});
$().data('key', 'val');
// setData Document utilities [{ event object }, "key", "val"]
$().data('key');
// getData Document utilities [{ event object }, "key"]

このイベント自体は問題ないのですが、名前空間を使用した場合その扱いが通常と異なり、keyの内容によってはイベントが発生しないことがあります。

$().bind('getData', function () {
    console.log('getData', this, arguments);
});
$().bind('setData', function () {
    console.log('setData', this, arguments);
});
$().bind('getData.aaa', function () {
    console.log('getData.aaa', this, arguments);
});
$().bind('setData.aaa', function () {
    console.log('setData.aaa', this, arguments);
});
$().data('key.aaa', 'aaa');
// setData.aaa Document utilities [{ event object }, "key", "aaa"]
// (setDataは発生しない)
$().data('key.aaa');
// getData.aaa Document utilities [{ event object }, "key"]
// (getDataは発生しない)

通常のイベントでは名前空間の指定無しでイベントを貼り付けた場合、呼び出し時の名前空間指定によらずイベントが呼び出されますが、getData、setDataイベントでは名前空間指定無しで貼り付けられた場合、名前空間指定無しの呼び出しにしか反応しません。 (ただ、getData、setDataイベントは通常のイベントと若干性格が違うので、これは意図した動作なのかもしれません)

他にもgetData、setDataイベントは名前空間処理が通常のイベントと別に記述されているため以下のような制限があります。

  • 名前空間順の未サポート(「key.name2.name1」の場合「name1」に設定されたイベントは呼び出されません)
  • 複数名前空間の未サポート(「key.name1.name2」の場合「name1」のみ名前空間として認識されます)

key固定の形であれば問題ありませんが、keyが動的に変わる場合「.」が含まれるかどうかでイベントが呼び出されない可能性があるので注意しましょう。

2 複数名前空間

jQueryでは複数名前空間をサポートしており、以下のような記述が可能になっています。

$().bind('click.hoge.huga', function () {
    console.log('click.hoge.huga');
});
$().trigger('click.huga');
// click.hoge.huga
$().trigger('click.piyo');
// 何も呼ばれない 

ただ、jQuery 1.3.2ではこの処理にバグがあり、次のような場合に問題が発生します。

$().bind('click.abc.deffffffffffff.ghi', function () {
    console.log('click.abc.deffffffffffff.ghi');
}); 
$().trigger('click.abc.def.ghi');
// click.abc.deffffffffffff.ghi 

これに関してはjQuery本家にもバグレポートがあがっているので、次のパージョンでは修正されていると思います。

また、この問題に関しては3個以上の名前空間を指定したときのみ発生するので、jQuery 1.3.2で名前空間を使用する場合、2個以上の名前空間を使用しないよう気をつけましょう。

3 ajax events(global events)

すべての$.ajaxの通信を取得するglobal eventsですが、一度設定すると以後$.ajax通信時にすべてのjQuery.cacheをなめることになります。

2625:   jQuery.each( jQuery.cache, function(){
2626:       if ( this.events && this.events[type] )
2627:           jQuery.event.trigger( event, data, this.handle.elem );
2628:   });

jQuery.cacheは過去にイベントが設定された要素がすべて格納されているため、イベントを多用する場合多くの要素が格納される可能性があります。

また、この処理は一度global eventsを設定すると、すべてのglobal eventsをunbindしても処理が行われるので注意してください。 (jQuery.events.global['event_name']をdeleteすることで処理が行われなくなります)

$().bind('ajaxComplete', function () {
    console.log('ajaxComplete');
});
$.get('/', function () {});
// ここでjQuery.cacheをすべてなめる 

$().unbind('ajaxComplete');
$.get('/', function () {});
// unbindしてもjQuery.cacheをすべてなめる 

delete jQuery.events.global['ajaxComplete'];
$.get('/', function () {});
// jQuery.cacheを無視する 

global eventsを使用する場合、.live eventsやjQueryのイベントを使用しない等の方法を使ってjQuery.cacheを肥大化させないよう注意しましょう。

4 引数無し$().removeData()

引数無しで.removeDataを呼び出した場合、指定された要素の.dataで保存された内容だけでなくイベントも一緒に削除します。

$().click(function () {
    console.log('click');
});
$().removeData();
$().click();
// 何も表示されません。 

もしイベントを残したまま.dataで保存した内容のみを削除したい場合、以下のような方法を使用する必要があります。 (書いてて自分でも信じられないので、他によい方法をご存じの方は是非教えてください

var target_elem = 'body';
$(target_elem).data('hoge', 'huga');
$(target_elem).click(function () {
    console.log('click');
});
// events,handle以外を削除 
$.each(jQuery.cache[$.data($(target_elem).get(0))], function (key, val) {
    if (key === 'events' || key === 'handle') return;
    $(target_elem).removeData(key);
});
$(target_elem).click();
// click 

5 長い配列を引数とした$.each

jQueryの.eachは長い配列を引数としたloopがあまり得意ではありません。

forEach色々とベンチマーク - 0xFF

リンク先はベンチマークなのであまり現実的な状況ではありませんが、ある程度大きな配列を回す場合には素のfor等の使用をお勧めします。

jQuery 1.3.2のソースを読んで気づいた点をまとめてみましたが、一部ドキュメント化されていない内容も入っているのでご注意ください。

カヤックでは本気の技術者を募集しています!

関連記事

(2010/08/11 getData、setDataイベントに関して追記しました。数字を0から数えるようにしました)