js观察者模式

发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态改变时,所有依赖于它的对象都将得到通知.详细demo可以参考observer.js

DOM事件

实际上我们在DOM节点上绑定事件处理函数,就是一种发布-订阅模式

   document.body.addEventListener('click', function(){
       alert(2);
   }, false);
   document.body.click(); //模拟用户点击

当body节点被点击时,body节点便会向订阅者发布这个消息。当然我们还可以随意增加或者删除订阅者,增加任何订阅者都不会影响发布者代码的编写

   document.body.addEventListener('click', function(){
       alert(3);
   }, false);
   document.body.addEventListener('click', function(){
       alert(4);
   }, false);

注意,手动触发事件更好的做法是IE下用fireEvent,标准浏览器下用dispatchEvent

自定义事件

比如我们实现一个天气预报的广播功能

   var weatherCenter = {};
   //缓存列表,存放订阅者的回调函数
   weatherCenter.clientList = [];
   weatherCenter.listen = function(fn){
      this.clientList.push(fn);
   }
   weatherCenter.trigger = function(){
      for(var i = 0, fn; i < this.clientList.length; i++){
          fn = this.clientList[i];
          fn.apply(this, arguments);
      }
   }

下面我们进行一些简单的测试

   //小明订阅消息(自定义回调函数,也就是自定义订阅消息的推送格式)
   weatherCenter.listen(function(type, temprature){
       console.log('温度=' + temprature);
       console.log('天气类型为' + type);
   })
   //小红订阅消息b 
   weatherCenter.listen(function(type, temprature){
       console.log('温度=' + temprature);
       console.log('天气类型为' + type);
   })   
   weatherCenter.trigger('rainy', '12');
   weatherCenter.trigger('sunny', '30');

至此,我们实现了简单的发布-订阅模式,但这里还有一点问题,假如小明只想知道晴天的天气推送,那么我们有必要增加一个标识key,让订阅者只订阅自己感兴趣的消息

   var weatherCenter = {};
   weatherCenter.clientList = {};
   weatherCenter.listen = function(key, fn){
       if(!this.clientList[key]){
           this.clientList[key] = [];
       }
       this.clientList[key].push(fn);
   }
   weatherCenter.trigger = function(){
       var key = Array.prototype.shift.call(arguments),
          //取出该消息对应的回调函数集合
          fns = this.clientList[key];
       if(!fns || fns.length === 0){
          return false;
       }
       for(var i = 0; i < fns.length; i++){
          //arguments对象的第一个参数已经被shift
          fn.apply(this, arguments);
       }
   }
   weatherCenter.listen('sunny', function(temprature){
       console.log('温度=' + temprature);
   })
   weatherCenter.listen('rainy', function(temprature){
       console.log('温度=' + temprature);
   })
   weatherCenter.trigger('rainy', '14');
   weatherCenter.trigger('sunny', '30');

发布-订阅模式的通用实现

我们假设小明又去其他气象中心订阅了天气,那这段代码是否应该在另一个气象中心上重写一次呢,有没有办法可以让所有对象都拥有发布-订阅功能呢
所以我们把发布-订阅的功能提取出来,放在一个单独的对象内

   var event = {
      clientList = [],
      listen: function(key, fn){
         if(!this.clientList[key]){
            this.clientList[key] = [];
         }
         this.clientList[key].push(fn);
      },
      trigger: function(){
         var key = Array.prototype.shift.call(arguments),
           fns = this.clientList(key);
         if(!fn || fn.length === 0){
            return false;
         }
         for(var i = 0, fn; fn = fns[i++]){
            //arguments对象的第一个参数已经被shift
            fn.apply(this, arguments);
         }
      }
   }

再定义一个installEvent函数,这个函数可以给所有的对象都动态安装订阅-发布功能

   var installEvent = function(obj){
      for(var i in obj){
         obj[i] = event[i];
      }
   }
   var weatherCenter = {};
   installEvent(weatherCenter);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值