js學習心得之js的自定義事件-基於觀察者模式的實現
阿新 • • 發佈:2019-01-27
GOF對觀察者模式的定義:Observer的意圖是定義物件之間的一種一(被觀察者)對多(觀察者)的關係,當一個物件的狀態發生改變時,所有依賴它的物件得到通知,並且會自動更新自己。
從這段經典的定義中,可以推測下,觀察者模式中的倆個物件各自應該擁有的特徵
1,被觀察者應該可以註冊觀察者,登出觀察者。
2,持有對其註冊的觀察者。
3,當自身改變時,依賴於特性一,其可以通知對其註冊的觀察者。
4,觀察者會自動更新自己。
5,被觀察者應該是獨立的,也就是說,觀察者影響其並不會影響被觀察者。
java與js的事件機制都可以說觀察者模式的應用場景。
在java的世界中藉助於
java.util.Observable
java.util.Observer
中這倆個類可以非常簡便的實現觀察者模式-(java的awt的事件機制在底層就是藉助觀察者模式實現的,這也可以算是搭建java世界中事件機制的支撐基礎類了)
對於js的事件,譬如,在一個DOM元素(被觀察者)上的單擊事件,觀察者(也就是在這個事件上的回撥函式)會關注這個很特別的時刻,並且做出反應。
在寫js的自定義事件之前,先看一下曾經令我十分好奇的EXT的自定義事件
部分程式碼來自 《深入淺出EXTJS》和《javascript高階程式設計》(第二版)
Person=function(name){
this.name=name;
this.addEvents('work','read');
};
Ext.extends(Person,Ext.util.Observable);
當自定義的類繼承了Ext.util.Observable後,自定義的類便可以支援事件。
var sz=new Person('sz');
sz.on('work',function(){//為Person的例項繫結監聽,即把觀察者註冊到要被觀察者
Ext.Msg.alert('宋崢,在工作那!');
});
下面,來觸發這個事件,其實原理很簡單,就是讓'work'事件對應處理函式執行。
sz.fireEvent('work');//回撥函式執行
很神奇,其實這就是封裝的力量,EXT對原生js的封裝,讓實現自定義事件變的如此簡單。
來看看《javascript高階程式設計》(第二版)對是自定義事件的實現(有小改動)。
對EXT自定義的事件的實現的原理?是不是已經相當透徹了?是不是可以聯絡到觀察者設計模式?
function Obserable(){
this.handlers={};//持有事件處理函式
}
Obserable.prototype={//重寫EventTarget的原型物件
constructor:EventTarget,
on:function(type,handler){//對應於觀察者模式-在相應的被觀察者註冊觀察者
//handlers中是否已有針對此事件型別的陣列
//沒有建立一個空陣列
//把這個處理函式推入對應的handlers[type]陣列,
if(typeof this.handlers[type]=="undefined"){
this.handlers[type]=[];
}
this.handlers[type].push(handler);
},
fireEvent:function(event){
if(!event.target){
event.target=this;
}
if(this.handlers[event.type] instanceof Array){
var handlers=this.handlers[event.type];//檢出被觀察者註冊的觀察者
for(var i=0;len=handlers.length;i++){
handlers[i]();//回撥函式執行,也就是觀察者更新自己
}
}
}
};
function handlerMessage(event){
alert("處理函式被回撥");
}
var ob=new Obserable();
ob.on('message',handlerMessage);
ob.fireEvent({type:'message'});
至此,只要繼承了此Obserable類的相應類的例項都可以成為被觀察者了,也就都可以支援事件了,這也就和EXT的自定義事件的思路沒多大差異了,當然EXT的設計更加巧妙。越來越有看EXT原始碼的慾望了,但水平還不夠,還需努力。
最後,不難發現,原生態的事件,是在某一個特殊時刻(單擊,獲得焦點等等)發生時,由遊覽器把這一特殊時刻的一些資訊,譬如事件型別,和其他的一些必要資訊封裝成event物件,觸發事件處理程式時把這個event物件作為實參傳入,而我們自定義的事件,當然只能由我們自己觸發,傳入的實參event也是我們自己傳入的(這個event,想封裝什麼就封裝什麼,需要什麼就封裝什麼).
從這段經典的定義中,可以推測下,觀察者模式中的倆個物件各自應該擁有的特徵
1,被觀察者應該可以註冊觀察者,登出觀察者。
2,持有對其註冊的觀察者。
3,當自身改變時,依賴於特性一,其可以通知對其註冊的觀察者。
4,觀察者會自動更新自己。
5,被觀察者應該是獨立的,也就是說,觀察者影響其並不會影響被觀察者。
java與js的事件機制都可以說觀察者模式的應用場景。
在java的世界中藉助於
java.util.Observable
java.util.Observer
中這倆個類可以非常簡便的實現觀察者模式-(java的awt的事件機制在底層就是藉助觀察者模式實現的,這也可以算是搭建java世界中事件機制的支撐基礎類了)
對於js的事件,譬如,在一個DOM元素(被觀察者)上的單擊事件,觀察者(也就是在這個事件上的回撥函式)會關注這個很特別的時刻,並且做出反應。
在寫js的自定義事件之前,先看一下曾經令我十分好奇的EXT的自定義事件
部分程式碼來自 《深入淺出EXTJS》和《javascript高階程式設計》(第二版)
Person=function(name){
this.name=name;
this.addEvents('work','read');
};
Ext.extends(Person,Ext.util.Observable);
當自定義的類繼承了Ext.util.Observable後,自定義的類便可以支援事件。
var sz=new Person('sz');
sz.on('work',function(){//為Person的例項繫結監聽,即把觀察者註冊到要被觀察者
Ext.Msg.alert('宋崢,在工作那!');
});
下面,來觸發這個事件,其實原理很簡單,就是讓'work'事件對應處理函式執行。
sz.fireEvent('work');//回撥函式執行
很神奇,其實這就是封裝的力量,EXT對原生js的封裝,讓實現自定義事件變的如此簡單。
來看看《javascript高階程式設計》(第二版)對是自定義事件的實現(有小改動)。
對EXT自定義的事件的實現的原理?是不是已經相當透徹了?是不是可以聯絡到觀察者設計模式?
function Obserable(){
this.handlers={};//持有事件處理函式
}
Obserable.prototype={//重寫EventTarget的原型物件
constructor:EventTarget,
on:function(type,handler){//對應於觀察者模式-在相應的被觀察者註冊觀察者
//handlers中是否已有針對此事件型別的陣列
//沒有建立一個空陣列
//把這個處理函式推入對應的handlers[type]陣列,
if(typeof this.handlers[type]=="undefined"){
this.handlers[type]=[];
}
this.handlers[type].push(handler);
},
fireEvent:function(event){
if(!event.target){
event.target=this;
}
if(this.handlers[event.type] instanceof Array){
var handlers=this.handlers[event.type];//檢出被觀察者註冊的觀察者
for(var i=0;len=handlers.length;i++){
handlers[i]();//回撥函式執行,也就是觀察者更新自己
}
}
}
};
function handlerMessage(event){
alert("處理函式被回撥");
}
var ob=new Obserable();
ob.on('message',handlerMessage);
ob.fireEvent({type:'message'});
至此,只要繼承了此Obserable類的相應類的例項都可以成為被觀察者了,也就都可以支援事件了,這也就和EXT的自定義事件的思路沒多大差異了,當然EXT的設計更加巧妙。越來越有看EXT原始碼的慾望了,但水平還不夠,還需努力。
最後,不難發現,原生態的事件,是在某一個特殊時刻(單擊,獲得焦點等等)發生時,由遊覽器把這一特殊時刻的一些資訊,譬如事件型別,和其他的一些必要資訊封裝成event物件,觸發事件處理程式時把這個event物件作為實參傳入,而我們自定義的事件,當然只能由我們自己觸發,傳入的實參event也是我們自己傳入的(這個event,想封裝什麼就封裝什麼,需要什麼就封裝什麼).