事件模塊Backbone.Events是Backbone的核心,Model、Collection、View都依賴它。 數組
此外,事件模塊的全部方法都掛在了全局的Backbone上,若是你的代碼中須要用到自定義事件(實現觀察者模式),能夠直接使用它。 數據結構
標示符Events是內部的一個引用,爲討論方便,這裏也省去了前綴Backbone。 閉包
1.0以前只提供了三個基本方法 on/once/off/trigger,1.0開始增長了幾個實用方法 listenTo/listenToOnce/stopListening。 函數
如下是各個方法的意義 性能
var Events = Backbone.Events = { on: function(name, callback, context) { // ... }, once: function(name, callback, context) { // ... }, off: function(name, callback, context) { // ... }, trigger: function(name) { // ... }, stopListening: function(obj, name, callback) { // ... } }; var eventSplitter = /\s+/; var eventsApi = function(obj, action, name, rest) { // ... }; var triggerEvents = function(events, args) { // ... }; var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; _.each(listenMethods, function(implementation, method) { Events[method] = function(obj, name, callback) { // ... }; }); Events.bind = Events.on; Events.unbind = Events.off; _.extend(Backbone, Events);
1. 先定義了一個對象(單例),直接掛上了接口方法on/once/off/trigger/stopListening,注意雖然Events頭字母大寫,這裏不是定義一個類或構造器,而是一個單例對象。 this
剩下的變量和函數都是輔助這個對象的,它們都在閉包空間裏,外部不可訪問如eventSplitter、eventsApi等 spa
2. eventSplitter用來實現空格間隔一次添加多個事件,如 .on('event1 event2', handler) prototype
3. eventsApi實現的很巧妙,它輔助on/once、off、trigger完成事件的添加、刪除、派發。 rest
4. triggerEvent輔助trigger方法實現派發事件,它的實現有些特殊,見 冗餘換性能 code
5. 後面的listenMethod和一個each迭代,會給Events添加兩個新方法listenTo和listenToOnce
6. 再下面兩行給on/off分別取了別名bind/unbind。其實這也是爲了兼容老版本,最先的版本添加/刪除事件爲bind/unbind。
7. 最後一行把Events摻合到全局的Backbone對象上了
拓撲圖以下
相對來講,目前的內部數據結構比較簡單。採用傳統的先哈希,後數組存儲事件處理器對象,處理器對象上有callback和context及ctx。其內部有兩個關鍵對象_eventshe _listeners,都如下劃線開頭,說明這是私有的(並不是真正私有,一種語法約定,真正私有可以使用閉包實現),僅供內部使用。
_events 這個哈希是默認是掛在Backbone.Events上,因爲Events是一個對象,因此很容易被Mix到任何想增長自定義事件的類或對象上。此時_events則掛在該對象上。如Backbone.Model,Backbone.Collection,Backbone.View,當給其實例添加自定義事件時,_events則掛在它們的實例對象上。
_events的結構以下
_.extend(Backbone, Events);
_listeners 和 _events同樣默認也是掛在Backbone.Events上。顧名思義,它是一個監聽器,便可覺得其它對象(具備Backbone.Events的全部方法的對象)被添加事件。它的key是以字母「l」開頭後跟遞增的數字組成,value是一個 「a mixin of Backbone.Events」。
_listeners的結構以下
最後又把Events上的全部方法都拷貝到標示符Backbone這個全局對象上,即給Backbone添加了以下方法。這時能夠很方便的使用它給本身的類添加自定義事件。
事件名「all」,在trigger方法中,仔細看代碼,你會發現trigger方法中調用了兩次triggerEvents,一次是經過參數傳進來的事件,另外一次則固定爲「all」事件。
var events =this._events[name]; var allEvents =this._events.all; if (events) triggerEvents(events, args); if (allEvents) triggerEvents(allEvents, arguments);
trigger的一般實現只需把事件名,參數傳進來,取哈希(這裏是_events)上取該事件的全部handlers(存在在數組裏),挨個執行。但這裏爲何每一次trigger調用還要單獨取下all事件,而後執行呢?
若是隻看Backbone.Events模塊,是很難理解的。那麼就搜索下整個Backbone.js,看「all」事件在哪些地方使用到。最後發現只在Backbone.Collection中用到,且僅一處。
model.on('all',this._onMod事件elEvent,this);
只看這一行代碼,仍是難以理解。須要結合Backbone.Model和Backbone.Collection一塊兒看。
這裏先簡單說下,咱們知道這行代碼所在方法是Collection.add,在往collection中添加model時執行的,即添加的model都會註冊一個「all」事件。而當model自身銷燬(destroy)或修改(change)的時候,須要通知其所在Collection。
例如,model銷燬後,Collection須要在集合中把它刪除,Collection的長度也須要減一。model修改後,也須要通知Collection,這樣給Collection添加的change事件也會觸發。
這就是「all」事件的真正用途,之前曾想既然Backbone的View和通訊都依賴於jQuery,那麼事件模塊也徹底可使用$.Callbacks。未曾想到還有一個特殊的「all」事件。
來看下代碼
_.extend(Model.prototype, Events, { }) _.extend(Collection.prototype, Events, { }) _.extend(View.prototype, Events, { }) _.extend(Router.prototype, Events, { })
把事件模塊mixin到這幾個類的原型上去了。一句話,這些類都具備Pub/Sub的功能,即均可以實現自定義事件,它們之間也就能夠經過事件很方便的下降耦合。若是在加上數據、視圖、邏輯的分層效果,這就是整個Backbone的精華了。