最近,小编重新回顾了百度前端大牛张容铭的《JavaScript设计模式》一书,不得不推荐下这本书,因为讲得实在太精彩了,很生动,可谓是书回价值O(∩_∩)O,玩过Angularjs、Reactjs,Redux,了解过RxJS,实现原理都用到观察者模式,可见其重要性,以下便是我的学习总结~
观察者模式(Observer): 又称为发布-订阅者模式或者消息机制,主要作用是为了解决类或对象之间的耦合,解耦两个相互依赖的对象,使其依赖观察者的消息机制。适用场景比如团队成员用独立闭包模块进行模块开发,为了避免新模块与旧模块的严重耦合,即可采用观察者模式。
实现思想代码如下,引用自《JavaScript设计模式》一书
1 var Observer = (function(){ 2 //将消息容器作为静态私有变量存储,是为了防止消息队列暴露而被篡改 3 var __message = {}; 4 return { 5 //注册信息接口 6 regist:function(type,fn){ 7 if(typeof __message[type] === 'undefined'){ 8 __message[type] = [fn]; 9 }else{ 10 __message[type].push(fn); 11 } 12 }, 13 //发布信息接口 14 fire:function(type,args){ 15 if(!__message[type]) 16 return; 17 var events = { 18 type:type, 19 args:args || {} 20 }, 21 i = 0, 22 len = __message[type].length; 23 for(;i < len;i++){ 24 __message[type][i].call(this,events) 25 } 26 }, 27 //移除信息接口 28 remove:function(type,fn){ 29 if(__message[type] instanceof Array){ 30 var i = __message[type].length - 1; 31 for(;i > 0;i--){ 32 __message[type][i] === fn && __message[type].splice(i,1); 33 } 34 } 35 } 36 } 37 })(); 38 // 注册接口:将订阅者注册的消息推入消息队列中 39 // 发布接口:当观察者发布一个消息时将所有订阅者订阅的消息一次执行。 40 // 移除接口:将订阅者注销的消息从消息队列中注销
笔者室友是一位前端大牛,他的博文中也谈到了观察者模式的JS实现,思想是一样但代码实现有点不一样,于是我借用他的demo改造成自己的实现,代码如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>Document</title> 7 </head> 8 9 <body> 10 <div class="ez-led" id="clock">00:00:00</div> 11 12 <script type="text/javascript"> 13 var Observer = (function(){ 14 //将消息容器作为静态私有变量存储,是为了防止消息队列暴露而被篡改 15 var __message = {}; 16 return { 17 //注册信息接口 18 regist:function(type,fn){ 19 if(typeof __message[type] === 'undefined'){ 20 __message[type] = [fn]; 21 }else{ 22 __message[type].push(fn); 23 } 24 }, 25 //发布信息接口 26 fire:function(type,args){ 27 if(!__message[type]) 28 return; 29 var events = { 30 type:type, 31 args:args || {} 32 }, 33 i = 0, 34 len = __message[type].length; 35 for(;i < len;i++){ 36 __message[type][i].call(this,events) 37 } 38 }, 39 //移除信息接口 40 remove:function(type,fn){ 41 if(__message[type] instanceof Array){ 42 var i = __message[type].length - 1; 43 for(;i >= 0;i--){ 44 __message[type][i] === fn && __message[type].splice(i,1); 45 } 46 } 47 } 48 } 49 })(); 50 51 window.onload = function() { 52 var elClock = document.getElementById('clock'); 53 var getTime = function() { 54 var _ = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09'], //补零 55 d = new Date(), 56 h = d.getHours(), 57 m = d.getMinutes(), 58 s = d.getSeconds(); 59 return [_[h] || h, _[m] || m, _[s] || s].join(":"); 60 } 61 elClock.textContent = getTime(); 62 63 function renderClock(data){ 64 elClock.textContent = data.args.msg; 65 } 66 67 //注册渲染时钟消息 68 Observer.regist('renderClockMessage',renderClock) 69 70 setInterval(function(){ 71 //每隔1s钟,发布渲染时钟消息 72 Observer.fire('renderClockMessage',{msg:getTime()}) 73 },1000) 74 } 75 </script> 76 </body> 77 </html>
参考注明: