觀察者模式又叫作發佈訂閱模式,它定義了一種一對多的關係,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生改變時就會通知全部觀察着對象。 它是由兩類對象組成,主題和觀察者,主題負責發佈事件,同時觀察者經過訂閱這些事件來觀察該主體,發佈者和訂閱者是徹底解耦的,彼此不知道對方的存在,二者僅僅共享一個自定義事件的名稱。html
在Nodejs中經過EventEmitter實現了原生的對於這一模式的支持。html5
在JavaScript中事件監聽機制就能夠理解爲一種觀察者模式。經過onclick進行事件綁定,而後經過交互行爲進行觸發或者事件主動觸發。數組
下面給出一個JS自定義的PubSub,仔細閱讀下面這段代碼有助於你理解觀察者模式。app
1、定義觀察者類Pubsub測試
/* Pubsub */ function Pubsub(){ //存放事件和對應的處理方法 this.handles = {}; }
2、實現事件訂閱onthis
//傳入事件類型type和事件處理handle on: function (type, handle) { if(!this.handles[type]){ this.handles[type] = []; } this.handles[type].push(handle); }
3、實現事件發佈emitspa
emit: function () { //經過傳入參數獲取事件類型 var type = Array.prototype.shift.call(arguments); if(!this.handles[type]){ return false; } for (var i = 0; i < this.handles[type].length; i++) { var handle = this.handles[type][i]; //執行事件 handle.apply(this, arguments); } }
須要說明的是Array.prototype.shift.call(arguments)這句代碼,arguments對象是function的內置對象,能夠獲取到調用該方法時傳入的實參數組。
shift方法取出數組中的第一個參數,就是type類型。prototype
4、實現事件取消訂閱offcode
off: function (type, handle) { handles = this.handles[type]; if(handles){ if(!handle){ handles.length = 0;//清空數組 }else{ for (var i = 0; i < handles.length; i++) { var _handle = handles[i]; if(_handle === handle){ handles.splice(i,1); } } } } }
完整代碼:htm
/* Pubsub */ function Pubsub(){ //存放事件和對應的處理方法 this.handles = {}; } Pubsub.prototype={ //傳入事件類型type和事件處理handle on: function (type, handle) { if(!this.handles[type]){ this.handles[type] = []; } this.handles[type].push(handle); }, emit: function () { //經過傳入參數獲取事件類型 var type = Array.prototype.shift.call(arguments); if(!this.handles[type]){ return false; } for (var i = 0; i < this.handles[type].length; i++) { var handle = this.handles[type][i]; //執行事件 handle.apply(this, arguments); } }, off: function (type, handle) { handles = this.handles[type]; if(handles){ if(!handle){ handles.length = 0;//清空數組 }else{ for (var i = 0; i < handles.length; i++) { var _handle = handles[i]; if(_handle === handle){ handles.splice(i,1); } } } } } }
5、測試
var p1 = new Pubsub(); p1.on('mm', function (name) { console.log('mm: '+ name); }); p1.emit('mm','哈哈哈哈'); console.log('==============='); var p2 = new Pubsub(); var fn = function (name) { console.log('mm2: '+ name); }; var fn2 = function (name) { console.log('mm222: '+ name); }; p2.on('mm2', fn); p2.on('mm2', fn2); p2.emit('mm2','哈2哈2哈2哈2'); console.log('-------------'); p2.off('mm2', fn); p2.emit('mm2','哈2哈2哈2哈2'); console.log('-------------'); p2.off('mm2'); p2.emit('mm2','哈2哈2哈2哈2'); console.log('-------------');
有關JavaScript的技術要點文章請看上海尚學堂:《JavaScript的文檔對象模型DOM》;《js 大廈之JavaScript事件》;《細說JavaScript BOM》等,請多多關注。