【オリジナル】backbone 1.1.0ソース解析のEvents

38655 ワード

最近nodeのソースコードを見ていますが、backboneの応用はまだ広いです.でも、前の勉強はすっかり忘れてしまいました.その時はメモをしていなかったことを後悔しています.
だから、いかんせん使いたいのはもっと良くて、ソースコードをはっきり見なければなりません.だからやはりソースコードの注釈ノートを残して、自分のために忘れようとします.
 
まず、ここではBackbone.Eventsの実装コードの注釈です.これはバックエンドのnodejs部分であれ、イベントベースのメカニズムの一つです.
すべてとても広い作用を持っています.さらにnodejsの非同期のメカニズムはもっと必要です.いくつかのロジックの問題を処理します.(もちろんプロモーションはあなたのようなpbsubよりも非同期に適しています.ハ、私はただ事件のメカニズムを示すようなものです.
重要性ですね
 
以下はコードに対するコメントです.間違いがあれば指摘してください.
 
  1   // Backbone.Events
  2   // ---------------
  3 
  4   // A module that can be mixed in to *any object* in order to provide it with
  5   // custom events. You may bind with `on` or remove with `off` callback
  6   // functions to an event; `trigger`-ing an event fires all callbacks in
  7   // succession.
  8   //
  9   //     var object = {};
 10   //     _.extend(object, Backbone.Events);
 11   //     object.on('expand', function(){ alert('expanded'); });
 12   //     object.trigger('expand');
 13   //
 14   var Events = Backbone.Events = {
 15 
 16     // Bind an event to a `callback` function. Passing `"all"` will bind
 17     // the callback to all events fired.
 18     on: function(name, callback, context) {
 19       //
 20       // 1.          ,  eventsApi      ,  eventsApi  false,    return
 21       // 2.        ,    ,  return
 22       if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
 23       //                 , name      ( :click | custom)
 24       //
 25       this._events || (this._events = {});
 26       var events = this._events[name] || (this._events[name] = []);
 27 
 28       //       events    
 29       // _events : {
 30       //     click : [{
 31       //           callback : cb1,
 32       //           context : ctx1,
 33       //           ctx : ctx1 || this
 34       //     },{
 35       //           callback : cb2,
 36       //           context : ctx2,
 37       //           ctx : ctx2 || this
 38       //     }, ...],
 39       //     blur : [{...}, {...}, ...],
 40       //     ...
 41       // }
 42       events.push({callback: callback, context: context, ctx: context || this});
 43       return this;
 44     },
 45 
 46     // Bind an event to only be triggered a single time. After the first time
 47     // the callback is invoked, it will be removed.
 48     once: function(name, callback, context) {
 49       if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
 50       var self = this;
 51       //  callback    ,      newCallback     calllback,
 52       //     ,newCallback    callback  ,      callback     
 53       //     once               ,     callback      
 54       var once = _.once(function() {
 55         self.off(name, once);
 56         callback.apply(this, arguments);
 57       });
 58       //    callback,  off  
 59       once._callback = callback;
 60       //     .on()      
 61       return this.on(name, once, context);
 62     },
 63 
 64     // Remove one or many callbacks. If `context` is null, removes all
 65     // callbacks with that function. If `callback` is null, removes all
 66     // callbacks for the event. If `name` is null, removes all bound
 67     // callbacks for all events.
 68     off: function(name, callback, context) {
 69       var retain, ev, events, names, i, l, j, k;
 70       //
 71       // 1.         ,      ,  return
 72       // 2.             
 73       if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
 74       //    obj.off()    ,       obj        
 75       //      _events   
 76       if (!name && !callback && !context) {
 77         this._events = {};
 78         return this;
 79       }
 80 
 81       //   name  , obj.off(undefined, cb1, ctx1)
 82       //   name          ( _.keys(this._events))
 83       names = name ? [name] : _.keys(this._events);
 84 
 85       //   name  events
 86       for (i = 0, l = names.length; i < l; i++) {
 87         name = names[i];
 88         if (events = this._events[name]) {
 89           this._events[name] = retain = [];
 90 
 91           //   callback  context     
 92           //                     off  
 93           //         _events,                    _events 
 94           if (callback || context) {
 95             for (j = 0, k = events.length; j < k; j++) {
 96               ev = events[j];
 97               //       callback  context   ,      
 98               //    _callback   .once     callback    ,   evn.callback      , callback   _callback 
 99               if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
100                   (context && context !== ev.context)) {
101                 retain.push(ev);
102               }
103             }
104           }
105           //                ,        ,  _events   key
106           if (!retain.length) delete this._events[name];
107         }
108       }
109 
110       return this;
111     },
112 
113     // Trigger one or many events, firing all bound callbacks. Callbacks are
114     // passed the same arguments as `trigger` is, apart from the event name
115     // (unless you're listening on `"all"`, which will cause your callback to
116     // receive the true name of the event as the first argument).
117     trigger: function(name) {
118       if (!this._events) return this;
119       //      callback   
120       var args = slice.call(arguments, 1);
121       //          trigger
122       if (!eventsApi(this, 'trigger', name, args)) return this;
123       //          
124       var events = this._events[name];
125       //    all     (all          ,all               )
126       var allEvents = this._events.all;
127       //                   all     
128       //     ,all              all              
129       if (events) triggerEvents(events, args);
130       if (allEvents) triggerEvents(allEvents, arguments);
131       return this;
132     },
133 
134     // Tell this object to stop listening to either specific events ... or
135     // to every object it's currently listening to.
136     stopListening: function(obj, name, callback) {
137       var listeningTo = this._listeningTo;
138       if (!listeningTo) return this;
139       // 
140       var remove = !name && !callback;
141       //      (obj, {click: cb1, change: cb2})    
142       //           context  ,   this
143       if (!callback && typeof name === 'object') callback = this;
144       //      obj,         obj
145       //
146       if (obj) (listeningTo = {})[obj._listenId] = obj;
147       for (var id in listeningTo) {
148         obj = listeningTo[id];
149         obj.off(name, callback, this);
150         //           
151         // 1.        obj        ( name callback   )
152         // 2. obj             ,          ?
153         if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
154       }
155       return this;
156     }
157 
158   };
159 
160   // Regular expression used to split event strings.
161   var eventSplitter = /\s+/;
162 
163   // Implement fancy features of the Events API such as multiple event
164   // names `"change blur"` and jQuery-style event maps `{change: action}`
165   // in terms of the existing API.
166   // ({}, 'on', 'click blur', [function () {}, undefined])
167   var eventsApi = function(obj, action, name, rest) {
168     if (!name) return true;
169 
170     // Handle event maps.
171     //       
172     //  :(obj, 'on', {'click': function x () {}, 'blur': function xx () {}}, context)
173     if (typeof name === 'object') {
174       for (var key in name) {
175         //     action(on | off | once),           ,        。
176         obj[action].apply(obj, [key, name[key]].concat(rest));
177       }
178       return false;
179     }
180 
181     // Handle space separated event names.
182     //         (           )
183     //  :(obj, 'on', 'click blur', function () {}, context)
184     if (eventSplitter.test(name)) {
185       var names = name.split(eventSplitter);
186       for (var i = 0, l = names.length; i < l; i++) {
187         obj[action].apply(obj, [names[i]].concat(rest));
188       }
189       return false;
190     }
191 
192     return true;
193   };
194 
195   // A difficult-to-believe, but optimized internal dispatch function for
196   // triggering events. Tries to keep the usual cases speedy (most internal
197   // Backbone events have 3 arguments).
198   //        ,    arg   3     , call    ,
199   //   call  apply    (http://jsperf.com/function-versus-function-call-versus-function-apply)
200   var triggerEvents = function(events, args) {
201     var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
202     switch (args.length) {
203       case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
204       case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
205       case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
206       case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
207       default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
208     }
209   };
210 
211   var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
212 
213   // Inversion-of-control versions of `on` and `once`. Tell *this* object to
214   // listen to an event in another object ... keeping track of what it's
215   // listening to.
216   //   listenTo listernToOnce  
217   //    :
218   // 1.         obj    _listenId   id
219   // 2.      (    )    map  listeningTo  ,     id obj
220   // 3.  obj          this     
221   //         obj on  once         ,
222   //                        ,           ,   1,2                
223 
224   _.each(listenMethods, function(implementation, method) {
225     Events[method] = function(obj, name, callback) {
226       var listeningTo = this._listeningTo || (this._listeningTo = {});
227       var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
228       listeningTo[id] = obj;
229       //      (obj, {click: cb1, change: cb2})    
230       //           context  ,   this
231       if (!callback && typeof name === 'object') callback = this;
232       obj[implementation](name, callback, this);
233       return this;
234     };
235   });
236 
237   // Aliases for backwards compatibility.
238   //     
239   Events.bind   = Events.on;
240   Events.unbind = Events.off;
241 
242   // Allow the `Backbone` object to serve as a global event bus, for folks who
243   // want global "pubsub" in a convenient place.
244   //  Backbone          
245   _.extend(Backbone, Events);
おやすみなさい