社内の有志でやっている JavaScript 勉強会があり、それのお題で Backbone.js のソースコードを読み始めた。
http://documentcloud.github.com/backbone/docs/backbone.html
今日は頭から読んで Backbone.Events を終えて Backbone.Model の has まで。
Backbone.Events の trigger を読むのに時間がかかった。
trigger : function(eventName) { var list, calls, ev, callback, args; var both = 2; if (!(calls = this._callbacks)) return this; while (both--) { ev = both ? eventName : 'all'; if (list = calls[ev]) { for (var i = 0, l = list.length; i < l; i++) { if (!(callback = list[i])) { list.splice(i, 1); i--; l--; } else { args = both ? Array.prototype.slice.call(arguments, 1) : arguments; callback[0].apply(callback[1] || this, args); } } } } return this; }
- なんで while ループなのか、何回ループするのか、 both-- って何なのか、三項演算子は各ループでどう評価されるのか、などを細かく読み込んでいった
- while ループは both == 2 と both == 1 の二回実行される
- while ループの条件部分で both-- が評価されるので(後置のデクリメント)本体部分では both はそれぞれ 1, 0 となる
- both == 1 の場合は「指定されたイベント名のコールバック関数があれば順番に実行する」
- both == 0 の場合は「all というイベント名のコールバック関数があれば順番に実行する」
- trigger は .trigger('before_save', 1, 2, 3) のように呼び出してコールバック関数に引数を渡せるようだ
- arguments には仮引数の値も含まれるので(この場合は eventName)それはコールバック関数に渡したくないため slice で arguments の先頭を一個取っている(ループ一回目)
- ループ二回目では arguments はすでに仮引数の eventName の値を含んでいないので args には arguments をそのまま渡す
- ここもトリッキーでわかりづらいと思った
などと、だいたいケチをつけながら盛り上がっていた。
あとは CommonJS の場合の場合分けとか Backbone.Model の初期化処理はきれいですねとかいう話をした。参加者二人だけだったけど。