0-9
Android, iOSでのjQuery, jquip, zepto, jQ.Mobi, riddle初期化時間比較

PCではなくAndroid, iOSのみの時間なので注意

http://jsrun.it/kyo_ago/1Akw
何も読み込まない状態
5~10ms

http://jsrun.it/kyo_ago/pggf
jQueryを読み込んた初期化時間
300ms~500ms

http://jsrun.it/kyo_ago/jGTs
jquip.events.css.ajaxを読み込んだ初期化時間
80ms~150ms

http://jsrun.it/kyo_ago/e3B0
zepto load timeを読み込んだ初期化時間
80ms~150ms

http://jsrun.it/kyo_ago/XzUy
jQ.Mobi load timeを読み込んだ初期化時間
30ms~50ms

http://jsrun.it/kyo_ago/y3tX
riddle load timeを読み込んだ初期化時間
20ms~40ms

Android, iOSでそこまで時間に差はなかった(少なくとも傾向は全部一緒)
Androidは初期化時間が安定しないが、iOSはわりと安定してる感じだった。

iOS, AndroidでjQuery.support内の無効になるものリスト

http://jsrun.it/kyo_ago/yMBj

それぞれ以下のものが無効になる

2.1-update1
    checkOn
    doesAddBorderForTableAndCells
    focusinBubbles
    inlineBlockNeedsLayout
    optDisabled
    optSelected
    shrinkWrapBlocks
    subtractsBorderForOverflowNotVisible

Android 2.3.6, 2.2, iOS 4.2.1
    checkOn
    doesAddBorderForTableAndCells
    focusinBubbles
    inlineBlockNeedsLayout
    optDisabled
    shrinkWrapBlocks
    subtractsBorderForOverflowNotVisible



もしもjQueryでクラスっぽく書くなら

(※この記事はJavaScript Advent Calendar 2011 (フレームワークコース) : ATNDの15日目の記事です)

jQueryとクラスベースはうまく混ぜるのがむつかしいけど、こんな感じにすれば割とクラスっぽく書けると思う。

(function () {
    var $ = jQuery.sub();
    jQuery.klass = jQuery.klass || {};
    jQuery.klass.myKlass = $;
    var klassVar = ‘hoge’;
    $.fn.myMethod = function () { alert(klassVar); };
})();

(function () {
    var $ = jQuery.klass.myKlass.sub();
    $(window).myMethod(); // alert(‘hoge’);
})();

これで少なくとも継承とカプセル化はできる。
後は各klass内で$()で取得した結果がインスタンス的なものになるので各クラス内で処理すればいい。
ただ、一般的なOOPのようにクラスと呼び出しを分けるより、クラス定義の部分に処理を全て書き出して外部との通信はカスタムイベントかプラグイン的な呼び出し方がいいと思う。
クラスというより処理の切り出し方という感じかも。

これとURL dispatcherを混ぜるとそれなりに規模が大きくても割といける。
URL dispatcherは処理の階層化が難しいという問題があって、
/hoge/
/huga/
というディレクトリに対する処理を切り出すのは簡単だけど、
/hoge/foo
/hoge/bar
というディレクトリに対する処理を/hoge/共通処理と/hoge/foo、/hoge/bar個別処理で切り出すのは多少考える必要がある。
(/hoge/の共通処理をグローバルに定義すれば簡単だけど)

クラスっぽい書き方であれば処理の階層化ができるのでこのへんうまく書ける。

jQueryはそろそろ実装と仕様を分離すべきじゃないか

jQueryがでかすぎて小分け版のjQuipが出たり、スマホ向けのZepto.jsが出たりしてるけど、そろそろjQueryも仕様と実装を分離して、素のjQueryとそれ以外を分ける方向に進んだらいいんじゃないか。

このへんPythonはうまくやっててCPython、Jython、IronPython、PyPyって感じで上手く分かれてる(ように見える)

jQueryも今のJS実装はCjQuery的な名前にして「jQuery」はテスト群とドキュメントの名前にすれば、他のjQuery実装も並立しやすくなると思う。

各種実装は「*jQuery」的な名前にして、「jQueryテストカバー率nn%でxx環境向け」ッテ感じの表記にするか、CCっぽく「xx APIセットサポート」みたいな表記にすればわかりやすくていいと思う。

CC的な表記であればPluginも「xx APIセットバージョンn以上をサポートしているjQueryで動作します」的な表記にできるし。

(ライブラリ側から必要なAPIセットをサポートしているかどうかの指定ができるといいかも)

「やりたかったらできるんだから勝手にやればいい」ってのもあるけど、本家がこういう方向に進んでくれると互換ライブラリの作者も作りやすくなるしユーザもわかりやすくなって嬉しい。

jQueryのliveやdelegateは実際何をやってるのか

jQueryにはイベント制御のAPIとして、clickやmouseoverの元になるbindの他に、同じような呼び出し方のliveやdelegateが提供されている。
bindはDOM APIで提供されているaddEventListenerのwrapperだが、liveは以下のような実装になっている。

1. 第一引数のイベント名でdocument objectにlive用のイベントハンドラーをbindする
2. 1で設定したイベントハンドラー内でdocument object内に存在する要素上で発生したイベントを全てキャッチする
・イベントの発生元要素がbind時に設定されたセレクタに一致する場合、第二引数に指定されたユーザーのイベントハンドラーを呼び出す

これはもともと「多量の要素に対してbindするとUIをロックしてしまう」という問題の対策として知られていた手法だが、liveはそれをjQuery APIとして標準化したもの。

こういう実装になっているので、liveはbindと比べて以下のような特長がある。

・イベント設定時に要素が存在している必要がない

liveはよく「セレクタに対してイベントを設定するようなもの」と言われるが、実際セレクタはイベント設定時ではなくイベント発生時に評価されるためイベント設定時に要素があるかどうかは関係がない。
このため、live設定後に逐次追加される要素に対してのイベントや、DOM構築前にイベントを設定する場合などに使用できる。

・要素数とイベントハンドラーの設定回数が比例しない
通常のbindは対象とする要素に対して個々にイベントを設定するため、要素数に比例してbind時の負荷が高くなる問題があるが、liveはdocument objectに対して一度bindするだけなので要素数とイベント設定時の負荷は連動しない。
ただし、これはlive呼び出し前に$()している点は含めていない。
この問題を解決するにはdelegateを使うか、あえてDOM構築前の要素が取得できない段階でliveを設定することで回避できる。
(もしくは、jQuery内部で使用している特殊な形式のセレクタを使うこともできるが、APIドキュメント化されていないためオススメしない)

・イベントの発生順が通常のbindされたイベントハンドラー後
実装上、liveで設定されたイベントハンドラーはbindで設定されたイベントハンドラーの後に呼び出される。
このため、liveで設定したイベントからbindで設定したイベントをキャンセルする事ができない。
(bindで設定したイベントからliveで設定したイベントをキャンセルすることは可能。また、liveイベントからブラウザの標準動作をキャンセルすることは可能)

・イベント処理自体の負荷は増加
発生したイベントに対して「発生元要素が対象セレクタに一致するか?」を確認するため、通常bindしたイベント処理に対して負荷が高くなる。
通常そこまで問題になるレベルではないが、リソースが限られた環境や、全体に負荷が高い場合には注意。

・設定されたイベントは全てjQuery内部で処理される
bindを使用したイベント設定の場合、対象となる要素上で発生したイベントのみjQuery内で処理されるが、liveを使用したイベント設定の場合、全ての要素上で発生するイベントがjQuery内で処理されて、発生元要素が対象要素の場合、イベントハンドラーを呼び出す。
このような実装になっているため、mouseover、scroll、resize等の全体で発生頻度が高いイベントをliveで設定した場合、対象要素と関係ない要素で発生したイベントでもパフォーマンスに影響を与える可能性がある。

これまで上げた問題点の内、パフォーマンスに関してはdelegateを使うことで解決できる場合がある。

delegateはliveとbindの中間のような実装で、$()で指定した要素にbindはするが、バブリングしてきたイベントの発生元要素が第一引数のセレクタに一致した場合だけイベントハンドラーを呼び出す。
つまり、document objectに対してdelegateを行えば、liveを行ったのと同じような動作になる。
delegateはliveに対して以下のような特長がある。

・初期のイベント設定が高速
liveは最初に指定する$()の要素を実際は使用しないが、jQueryの仕様上$()で指定したセレクタに一致する要素は取得してしまう。
しかし、liveは大量の要素に対して素早くイベントを設置するために使われることが多いので、このままだと持ち味を生かすことができない。
これに対してdelegateは$()で指定した要素の取得は行うが、イベント発生元要素の指定はセレクタ文字列を渡すだけなので実際要素の取得は行わない。
このため、今後jQueryではlive方式ではなく、delegate方式が主流になると思う。
(jQuery 1.7で採用されたonもliveはおまけみたいな実装だし)
ちなみに、この問題に関しては「DOM構築前のまだ要素が存在しない段階でliveを行う」方法でも回避可能で、個人的にもこの方法をよく使っている

・bindする要素を指定できる
liveはdocument objectにbindする実装上、要素を破棄してイベントが解除されるということがほぼなく、JSで画面遷移を実装した場合各画面ごとのイベント破棄を確実に行う必要がある。
これに対してdelegateはbindする要素を指定することができるので、画面遷移時に破棄される要素を対象とすればイベントの破棄をあまり考える必要がない。
ただ、これはあまり嬉しい場面も多くないので、大抵はイベント設定の高速化が目的になるだろう。

delegateはliveと同じような説明でぱっと見何に使うのか分かりにくいが、後から追加されただけあってliveの問題点を解決する形になっている。
jQuery 1.7で追加されるonでもliveはおまけ的な扱いになっているし、個人的にもこれから触るならliveは忘れてdelegateメインで使うほうがいいと思う。
(まあでも書式が分かりやすいので、パフォーマンスに問題ない形で使ってるけど)