@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Backbone.Events (2)

社内の有志でやっている 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 というイベント名のコールバック関数があれば順番に実行する」
    • all というイベント名でイベントハンドラを登録しておくと、 trigger を呼んだときイベント名にかかわらず常に実行されるイベントハンドラをセットできるようだ
    • both はわかりづらいと思った
  • trigger は .trigger('before_save', 1, 2, 3) のように呼び出してコールバック関数に引数を渡せるようだ
  • arguments には仮引数の値も含まれるので(この場合は eventName)それはコールバック関数に渡したくないため slice で arguments の先頭を一個取っている(ループ一回目)
  • ループ二回目では arguments はすでに仮引数の eventName の値を含んでいないので args には arguments をそのまま渡す
    • ここもトリッキーでわかりづらいと思った

などと、だいたいケチをつけながら盛り上がっていた。

あとは CommonJS の場合の場合分けとか Backbone.Model の初期化処理はきれいですねとかいう話をした。参加者二人だけだったけど。