学习JavaScript设计模式之观察者模式
一、定义
观察者模式(发布-订阅模式):其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
在JavaScript中,一般使用事件模型来替代传统的观察者模式。
好处:
- (1)可广泛应用于异步编程中,是一种替代传递回调函数的方案。
- (2)可取代对象之间硬编码的通知机制,一个对象不用再显示地调用另外一个对象的某个接口。两对象轻松解耦。
二、DOM事件–观察者模式典例
需要监控用户点击document.body的动作,但是我们没有办法预知用户将在什么时间点击。
所以,我们订阅document.body上的click事件,当body节点被点击时,body节点便向订阅者发布这个消息!
document.body.addEventListener("click",function(){
console.log(1);
},false);
//可以多个订阅者
document.body.addEventListener("click",function(){
console.log(2);
},false);
doucment.body.click();
某网站有header头部、nav导航、消息列表等模块。这几个模块的渲染都需要获取用户登陆信息。
(1)一般写法:
$.ajax({
url:'./login',
type:'post',
contentType:'application/json',
dataType:'json',
success:function(data){
if(data.status==="success"){
//登录成功,渲染header、nav
header.setInfo(data.headerInfo);
nav.setInfo(data.navInfo);
}
}
});
(2)使用观察者模式,很轻松解耦!
$.ajax({
...,
success:function(data){
if(data.status==="success"){
//登录成功,发布登陆成功消息
login.trigger("loginsuccess",data);
}
}
});
varheader=(function(){
//监听消息
login.listen("loginsuccess",function(data){
header.setInfo(data.headerInfo);
});
return{
setInfo:function(data){
console.log("设置header信息");
}
};
})();
varnav=(function(){
login.listen("loginsuccess",function(data){
nav.setInfo(data.navInfo);
});
return{
setInfo:function(data){
console.log("设置nav信息");
}
}
})();
三、通用观察者模式
/*
*示例:
*Event.create("namespace1").listen('click',function(a){
*console.log(a);
*});
*Event.create("namespace1").trigger("click",1);
*/
varEvent=(function(){
varglobal=this,
Event,
_default='default';
Event=function(){
var_listen,
_trigger,
_remove,
_slice=Array.prototype.slice,
_shift=Array.prototype.shift,
_unshift=Array.prototype.unshift,
namespaceCache=[],
_create,
find,
each=function(ary,fn){
varret;
for(vari=0,l=ary.length;i<l;i++){
varn=ary[i];
ret=fn.call(n,i,n);
}
returnret;
};
//订阅
_listen=function(key,fn,cache){
if(!cache[key]){
cache[key]=[];
}
cache[key].push(fn);
};
//移除订阅
_remove=function(key,cache,fn){
if(cache[key]){
if(fn){
for(vari=cache[key].length;i>=0;i++){
if(cache[key][i]===fn){
cache[key].splice(i,1);
}
}
}else{
cache[key]=[];
}
}
};
//发布
_trigger=function(){
varcache=_shift.call(arguments),
key=_shift.call(arguments),
args=arguments,
_self=this,
ret,
stack=cache[key];
if(!stack||!stack.length){
return;
}
returneach(stack,function(){
returnthis.apply(_self,args);
});
};
//创建命名空间
_create=function(namespace){
varnamespace=namespace||_default;
varcache={},
offlineStack=[],//离线事件
ret={
listen:function(key,fn,last){
_listen(key,fn,cache);
if(offlineStack==null){
return;
}
if(last==='last'){
offlineStack.length&&offlineStack.pop()();
}else{
each(offlineStack,function(){
this();
});
}
offlineStack=null;
},
one:function(key,fn,last){
_remove(key,cache);
this.listen(key,fn,last);
},
remove:function(key,fn,last){
_remove(key,cache,fn);
},
trigger:function(){
varfn,
args,
_self=this;
_unshift.call(arguments,cache);
args=arguments;
fn=function(){
return_trigger.apply(_self,args);
};
if(offlineStack){
returnofflineStack.push(fn);
}
returnfn;
}
};
returnnamespace?(namespaceCache[namespace]?namespaceCache[namespace]:namespaceCache[namespace]=ret):ret;
};
return{
create:_create,
one:function(key,fn,last){
varevent=this.create();
event.one(key,fn,last);
},
remove:function(key,fn){
varevent=this.create();
event.remove(key,fn);
},
listen:function(key,fn,last){
varevent=this.create();
event.listen(key,fn,last);
},
trigger:function(){
varevent=this.create();
event.trigger.apply(this,arguments);
}
};
}();
returnEvent;
})();
希望本文所述对大家学习javascript程序设计有所帮助。