用了backbone一段時間了,作一些筆記和總結,看的源碼是1.12express
backbone有events,model,collection,histoty,router,view這些模塊,其中events是最基礎的,其餘的模塊的prototype所有都擴展了他,因此events是很是重要的,真的很重要,還好代碼比較簡單,也比較好理解數組
這個裏面的代碼是從backbone裏面剝離出來,而後一點一點研究和調試出來的,能夠單獨運行,依賴underscoreapp
1 (function(){ 2 this.Backbone = {}; 3 var array = []; 4 var slice = array.slice; 5 // Regular expression used to split event strings. 6 //劈開eventsApi函數裏面傳入name,若是name是帶空格的字符串 7 var eventSplitter = /\s+/; 8 9 // Implement fancy features of the Events API such as multiple event 10 // names `"change blur"` and jQuery-style event maps `{change: action}` 11 // in terms of the existing API. 12 //若是傳入的name(這個對應綁定 刪除 觸發 監聽的事件名)爲obj 或者是帶空格的字符串,則批量進行相關的操做 13 var eventsApi = function(obj, action, name, rest) { 14 if (!name) return true; 15 16 // Handle event maps. 17 if (typeof name === 'object') { 18 for (var key in name) { 19 obj[action].apply(obj, [key, name[key]].concat(rest)); 20 } 21 return false; 22 } 23 24 // Handle space separated event names. 25 if (eventSplitter.test(name)) { 26 var names = name.split(eventSplitter); 27 for (var i = 0, length = names.length; i < length; i++) { 28 obj[action].apply(obj, [names[i]].concat(rest)); 29 } 30 return false; 31 } 32 33 return true; 34 }; 35 36 37 38 var Events = Backbone.Events = { 39 // Bind an event to a `callback` function. Passing `"all"` will bind 40 // the callback to all events fired. 41 // 參數的傳入爲 事件名, 回調, 回調裏面this指向的對象 42 on: function(name, callback, context) { 43 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; 44 //對象內部生成一個_events對象 key對應事件名, value爲一個數組,裏面添加相關的回調函數 45 this._events || (this._events = {}); 46 var events = this._events[name] || (this._events[name] = []); 47 //第3個和第4個參數,表示回調函數觸發的是偶, 函數裏面this的指向 48 events.push({callback: callback, context: context, ctx: context || this}); 49 return this; 50 }, 51 // Bind an event to only be triggered a single time. After the first time 52 // the callback is invoked, it will be removed. 53 // 跟on同樣的入參 ,他只會執行一次 54 once: function(name, callback, context) { 55 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; 56 var self = this; 57 //真正綁定進_.events的事故once 而不是callback,當once執行完一次後,就從_events上面刪除掉了 58 var once = _.once(function() { 59 self.off(name, once); 60 callback.apply(this, arguments); 61 }); 62 once._callback = callback; 63 return this.on(name, once, context); 64 }, 65 66 // Trigger one or many events, firing all bound callbacks. Callbacks are 67 // passed the same arguments as `trigger` is, apart from the event name 68 // (unless you're listening on `"all"`, which will cause your callback to 69 // receive the true name of the event as the first argument). 70 trigger: function(name) { 71 if (!this._events) return this; 72 var args = slice.call(arguments, 1); 73 if (!eventsApi(this, 'trigger', name, args)) return this; 74 var events = this._events[name]; 75 var allEvents = this._events.all; 76 //經過name 找到對應的回調數組 依次執行裏面的回調 77 if (events) triggerEvents(events, args); 78 //查看是否綁定了all事件 若是綁定也會出阿發 79 if (allEvents) triggerEvents(allEvents, arguments); 80 return this; 81 }, 82 83 // Remove one or many callbacks. If `context` is null, removes all 84 // callbacks with that function. If `callback` is null, removes all 85 // callbacks for the event. If `name` is null, removes all bound 86 // callbacks for all events. 87 off: function(name, callback, context) { 88 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; 89 90 // Remove all callbacks for all events. 91 //若是參數不存在 就移除全部的事件 92 if (!name && !callback && !context) { 93 this._events = void 0; 94 return this; 95 } 96 97 var names = name ? [name] : _.keys(this._events); 98 for (var i = 0, length = names.length; i < length; i++) { 99 name = names[i]; 100 101 // Bail out if there are no events stored. 102 var events = this._events[name]; 103 if (!events) continue; 104 105 // Remove all callbacks for this event. 106 //若是隻傳遞name這一個參數 就刪除name對應的整個數組 107 if (!callback && !context) { 108 delete this._events[name]; 109 continue; 110 } 111 112 // Find any remaining events. 113 // 114 //若是若是傳遞了第2個參數 只刪除_events[name]裏面對應的callback 115 //若是傳遞了第2個參數,第3個參數,還要判斷_events[name]裏面的callback是否等於第2個參數,context是否等於第3個參數 116 //把那麼不符合條件的用remaining保存起來 117 //而後用this._events[name] = remaining替換掉以前的 118 var remaining = []; 119 for (var j = 0, k = events.length; j < k; j++) { 120 var event = events[j]; 121 if ( 122 callback && callback !== event.callback && 123 callback !== event.callback._callback || 124 context && context !== event.context 125 ) { 126 remaining.push(event); 127 } 128 } 129 130 // Replace events if there are any remaining. Otherwise, clean up. 131 if (remaining.length) { 132 this._events[name] = remaining; 133 } else { 134 delete this._events[name]; 135 } 136 } 137 138 return this; 139 }, 140 // Tell this object to stop listening to either specific events ... or 141 // to every object it's currently listening to. 142 stopListening: function(obj, name, callback) { 143 var listeningTo = this._listeningTo; 144 if (!listeningTo) return this; 145 var remove = !name && !callback; 146 if (!callback && typeof name === 'object') callback = this; 147 if (obj) (listeningTo = {})[obj._listenId] = obj; 148 for (var id in listeningTo) { 149 obj = listeningTo[id]; 150 obj.off(name, callback, this); 151 if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; 152 } 153 return this; 154 } 155 } 156 157 var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; 158 159 // Inversion-of-control versions of `on` and `once`. Tell *this* object to 160 // listen to an event in another object ... keeping track of what it's 161 // listening to. 162 // on listenTo 163 _.each(listenMethods, function(implementation, method) { 164 Events[method] = function(obj, name, callback) { 165 //obj 爲被監聽的對象 166 //name 爲被監聽的事件名 167 // callback 是obj觸發了name事件後, 別監聽到了 而後執行的回調 168 var listeningTo = this._listeningTo || (this._listeningTo = {}); 169 var id = obj._listenId || (obj._listenId = _.uniqueId('l')); 170 //給監聽對象添加一個_listeningTo的屬性 它的值是一個對象key爲_listenId value爲被監聽的對象 171 //被監聽對象添加一個_listenId的屬性 它的值爲_listenId 172 listeningTo[id] = obj; 173 174 if (!callback && typeof name === 'object') callback = this; 175 obj[implementation](name, callback, this); 176 return this; 177 }; 178 }); 179 180 // A difficult-to-believe, but optimized internal dispatch function for 181 // triggering events. Tries to keep the usual cases speedy (most internal 182 // Backbone events have 3 arguments). 183 //批量處理_events裏面的回調事件的東西 184 //參數小於等於3個用call 大於3個用apply 爲毛會這樣 185 var triggerEvents = function(events, args) { 186 var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; 187 switch (args.length) { 188 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; 189 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; 190 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; 191 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; 192 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; 193 } 194 }; 195 })();
Backbone.Eventsless
Events主要就是對object進行綁定,觸發,刪除,監聽,它有如下一些方法ide
on bind 綁定事件函數
trigger 觸發綁定事件this
off unbind 移除綁定事件spa
listenTo 監聽對象prototype
stopListening 中止監聽調試
on object.on(event, callback, [context])
綁定callback函數到object對象。 當事件觸發時執行回調函數callback。第一個參數是事件名,第2個參數是綁定的事件 第3個參數是一個對象,callback裏面若是有this,則this指向第3個參數,若是沒有傳遞第3個參數則callback裏面的this指向object自己
當綁定上一個事件的時候,該object會產生一個_events的屬性,該屬性是一個object類型,key對應的是事件名,value對應的是一個數組,數組裏面放的是全部的回調事件
當觸發一個事件的時候,它會遍歷_.events,根據傳遞的事件名,查找相關的回調事件,而後執行。若是綁定了all,則只要調用了trigger,就會調用all下面的全部的回調
一些例子
一個object能夠綁定多個事件,同一個事件能夠有多個回調
var test = {}; _.extend(test,Backbone.Events); test.on("a",function(){alert(1)}); test.on("a",function(){alert(11)}); test.on("b",function(){alert(2)}); test.trigger("a"); test.trigger("b"); //test綁定了2個事件a,b a綁定了2個回調函數
obj能夠批量綁定事件,就是第一個參數是個對象
var obj = {c:1} var test={}; _.extend(test,Backbone.Events); test.on({ "a" : function(){alert(1111)}, "b" : function(){alert(this.c)} },obj); test.trigger("b") //彈出1 //能夠一次綁定2個事件a,b 傳入的第3個參數是個obj,因此回調執行的時候this指向obj
若是指定綁定事件名爲all,觸發任何綁定事件的時候都會觸發該事件
var test = {}; _.extend(test,Backbone.Events); test.on("a",function(){alert(1)}); test.on("all",function(){alert(111)}); test.trigger("a"); //觸發a事件 也會自動觸發all事件
once object.on(event, callback, [context])
綁定callback函數到object對象。 當事件觸發時執行回調函數callback。 第3個參數是一個對象,callback裏面若是有this,則this指向第3個參數。
該綁定事件只能觸發一次,而後就會被移除掉
var test = {}; _.extend(test,Backbone.Events); test.once("a",function(){alert(1)}); console.log(test); //test._events裏面是有a屬性的 test.trigger("a"); console.log(test) //test._events裏面的a屬性就被刪除掉了 test.trigger("a");
trigger object.trigger(event, [*args])
經過事件名觸發對應的回調函數。events後面的參數做爲參數傳入回調事件裏面
var test = {}; _.extend(test,Backbone.Events); test.on("a",function(a){alert(a)}); test.on("a",function(a,b){alert(a+b)}); test.on("a",function(a,b,c){alert(a+b+c)}); test.trigger("a",1,2,3) //依次彈出1,3,6
off object.off([event], [callback], [context])
從object中刪除之前綁定的回調函數
第一個參數是事件名
第2個參數是指定的函數,若是傳了,就只刪除綁定在object上的該函數,若是沒傳,則移除全部的函數
第3個參數是指定對象,若是綁定的時候調用回調指定了對象,刪除的時候也要把該對象帶上
若是調用off的時候不傳遞參數,則刪除全部的綁定事件
var test = {}; _.extend(test,Backbone.Events); test.on("a",function(){alert(1)}) test.on("b",function(){alert(1)}) console.log(test._events) test.off() console.log(test._events) //刪除後test._events就是空的了
若是指定了刪除的事件名,而且傳遞了第2個參數,並且第2個參數是就是傳入的回調的事件,則只刪除該指定了回調函數
var test = {}; _.extend(test,Backbone.Events); var aFun = function(){alert(1)} test.on("a",aFun ) test.on("a",function(){alert(1)}) console.log(test._events); test.off("a",aFun) console.log(test._events); //只刪除了第二個參數指定的回調函數
listenTo object.listenTo(other, event, callback)
object監聽other對象上的指定的方法名上(好比a),若是other觸發a,則也會觸發監聽的回調(callback)
當一個對象監聽其餘對象的事件名的時候(好比a,b,2個對象,b綁定haha事件,a監聽b的haha事件),a對象會生成_listeningTo的對象,根據_.uniqueId("l")生成的值來作key,value則是b這個對象了。b對象則會生成一個屬性_listenId,他的值就是前面_.uniqueId("l")生成的值, 而後若是傳入了監聽事件的回調函數 再b._events.haha的回調數組中加入該函數,當b觸發haha的時候也就會觸發該函數了。
listenTo仍是很重要的,好比一個view,初始化的時候就去listento一個model,當model,的時候就會自動通知view去渲染頁面
第一個參數是要監聽的對象,
第二個參數是須要監聽的事件名
第三個參數是當被監聽者處罰了該事件,執行的回調
var test = {}; var other = {}; _.extend(test,Backbone.Events); _.extend(other,Backbone.Events); other.on("a",function(){alert(1)}) other.on("a",function(){alert(2)}) test.listenTo(other,"a",function(){alert("test")}) other.trigger("a") //test監聽other,當other觸發a時,先執行完ohter本身綁定的回調,在執行監聽回調