JavaScript原生實現觀察者模式

觀察者模式又叫作發佈訂閱模式,它定義了一種一對多的關係,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生改變時就會通知全部觀察着對象。 它是由兩類對象組成,主題和觀察者,主題負責發佈事件,同時觀察者經過訂閱這些事件來觀察該主體,發佈者和訂閱者是徹底解耦的,彼此不知道對方的存在,二者僅僅共享一個自定義事件的名稱。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》等,請多多關注。

相關文章
相關標籤/搜索