简介
观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
举一个现实生活中的例子,例如小红在淘宝的一家店里看上了一双红色的鞋,小李也在这家店里面看上了一顶黑色的帽子,但是联系卖家时,卖家回答这两样都没货了。卖家告诉小红小李,要是喜欢的话,可以关注下店铺,到货了,我会给大家通知的。这就是一个典型的发布-订阅模式,卖家是发布者,买家是订阅者。当货来的时候,会依次通知小红、小李等买家,依次给他们发消息通知。
代码实现
var goodsObj = {}; goodsObj.list = []; //存放订阅者 订阅者 goodsObj.subscribe = function(key,fn){ if(!this.list[key]){ this.list[key] = []; } 订阅的消息存放到缓存列表中 .list[key].push(fn); } 取消订阅 goodsObj.unsubscribe = var fns = .list[key]; 如果key对应的消息没有订阅过的话,则返回 fns){ return false; } 如果没有传入具体的回调函数,表示取消key对应消息的所有订阅 fn){ fns && (fns.length = 0); }else{ for(var i = fns.length - 1; i >= 0; i--){ if(fns[i] === fn){ 删除订阅者的回调函数 fns.splice(i,1); } } } } 发布者 goodsObj.publish = (){ var key = Array.prototype.shift.call(arguments); 如果没有订阅过该key的消息,直接返回 if(!fns || fns.length === 0){ var i = 0,fn; fn = fns[i++];){ fn.apply(,arguments); } } 小红订阅了鞋 goodsObj.subscribe('shoes',fn1 = (color){ console.log('订阅鞋的颜色:' + color + '到货了,可以拍了'); }); 小李订阅了帽子 goodsObj.subscribe('cap',fn2 = (size){ console.log('订阅帽子的尺寸:' + size + '到货了,可以拍了'发布 goodsObj.publish('shoes','red'); goodsObj.publish('cap',40); 取消订阅 goodsObj.unsubscribe('shoes'发布消息,看是否能收到 goodsObj.publish('shoes','block');
优化取消订阅
为了优化取消订阅,在订阅的时候,给每个订阅者一个不同的标识,代码如下:
{}; goodsObj.list = {}; 存放订阅者 var subuid = -1; 每个订阅者标识不一样 var token= (++subuid).toString(); .list[key].push({ token:token,fn:fn }); return token; } (token){ var m in goodsObj.list){ if(goodsObj.list.hasOwnProperty(m)){ ){ if(goodsObj.list[m][i].token == token){ goodsObj.list[m].splice(i,1); break; } } } } } ];){ obj.fn.apply(小红订阅了鞋 var token1 = goodsObj.subscribe('shoes',取消订阅 goodsObj.unsubscribe(token1); 订阅对象var Event = (var list = {},1)"> subscribe,unsubscribe,publish,subuid = -1; 每个订阅者标识不一样 订阅者 subscribe = list[key]){ list[key] = []; } 订阅的消息存放到缓存列表中 subuid).toString(); list[key].push({ token:token,fn:fn }); token; }; 取消订阅 unsubscribe = (token){ list){ (list.hasOwnProperty(m)){ ){ if(list[m][i].token == token){ list[m].splice(i,1)">); ; } } } } }; 发布者 publish = (){ Array.prototype.shift.call(arguments); var fns = list[key]; ){ ; } ];){ obj.fn.apply( { publish:publish,subscribe:subscribe,unsubscribe:unsubscribe } })(); var token1 = Event.subscribe('shoes',1)">小李订阅了帽子 Event.subscribe('cap',1)">发布 Event.publish('shoes',1)">); Event.publish('cap',1)">Event.unsubscribe(token1); 订阅对象来实现两个模块之间的通信问题;比如现在有一个页面有一个按钮,每次点击此按钮后,div中会显示此按钮被点击的总次数;如下代码:<button id="clickBtn">点击我计数</button> div ="showCount">0div>JS代码如下:
(var count = 0; 发布(责处理点击操作、发布消息) document.getElementById('clickBtn').addEventListener('click',1)">(){ Event.publish('add',count++); },); 订阅(负责监听add这个消息,并把点击的总次数显示到页面上来) Event.subscribe('add',1)">(curCount){ document.getElementById('showCount').innerHTML = curCount; }) })();var Event = var listen,obj,remove,one,trigger,__this; obj = {}; __this = ; listen = _ref,stack; stack = (_ref = obj[key]) != null ? _ref : obj[key] = []; stack.push(eventfn); }; one = listen(key,eventfn); }; remove = (key){ _ref; return (_ref = obj[key]) != null ? _ref.length = 0 : void 0; }; trigger = (){ fn,stack,_i,_len,_ref,key; key = Array.prototype.shift.call(arguments); stack = (_ref = obj[key]) != null ? _ref :obj[key] =for(_i=0,_len=stack.length;_i<_len;_i++){ fn = stack[_i]; if(fn.apply(__this,arguments) === ; } } } { listen:listen,one:one,remove:remove,trigger:trigger } } var addTv = Event(); addTv.listen('play',1)">(data){ console.log('今天上午要播放的电影是:' +data.name); }); addTv.one('play',1)">(data){ console.log('只有我订阅的电影信息:' +data.name); }); addTv.trigger('play',{'name':'国产凌凌漆'}); addTv.remove('play'); addTv.trigger('play',{'name':'国产凌凌漆22'});参考