学习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程序设计有所帮助。