zoukankan      html  css  js  c++  java
  • 轻松掌握:JavaScript观察者模式

    观察者模式

    观察者模式也叫“订阅者/发布者”模式,定义对象间的一种一对多的依赖关系,发布者可以向所有订阅者发布消息。

    观察者模式被广泛地应用于JavaScript客户端编程中。所有的浏览器事件(mouseover,keypress等)都是使用观察者模式的例子。

    使用这个模式的最主要目的就是促进对象之间的解耦(弱化对象之间的联系)。在观察者模式中,一组对象订阅另一个对象的指定活动并得到通知。

    如:

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

    以上代码订阅了document.body的click事件,当body被点击时,body便会向订阅者发布消息;

    实现观察者模式的一般步骤:

    1. 先指定谁充当发布者;
    2. 给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者;
    3. 发布消息时,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数;还可在回调函数内加入一些参数;
      (也可先发布消息,将消息保存起来,当有订阅者时就将该消息重新发布给他)
    发布-订阅模式的通用实现:
    var Publisher = (function(){
        //listenerList用来保存一系列的key,每个key为保存了所有订阅者函数fn的数组{ keyA:[fn1,fn2...], keyB:[...]...}
        //类似:可以为同一事件注册多个回调函数
        var listenerList = {};
        return {
            addListener: function(key,fn){
                if(!listenerList[key]){
                    listenerList[key] = [];
                }
                if(listenerList[key].indexOf(fn) === -1){ //检测fn是否已订阅,注意indexOf方法不支持IE9以下,可用for循环代替
                    listenerList[key].push(fn);
                }
            },
            publish: function(){
                var key = Array.prototype.shift.call(arguments),
                    fns = listenerList[key];
                if(!fns||fns.length === 0){
                    return false;
                }
                for(var i = 0,fn;fn = fns[i++];){
                    fn.apply(this,arguments);
                }
            },
            removeListener: function(key,fn){
                var fns = listenerList[key];
                if(!fns){
                    return false;
                }
                if(!fn){ //若没指定fn,则表示取消所有订阅
                    fns && (fns.length = 0);
                }else{  //可直接用fns.splice(listenerList[key].indexOf(fn),1);但indexOf方法不支持IE9以下
                    for(var l = fns.length - 1; l >=  0; l--){
                        if(fns[l] === fn){
                            fns.splice(l,1);
                        }
                    }
                }
            }
        };
    })();
    
    Publisher.addListener('month',function(num){  //订阅month
        console.log('本月数量: '+num);
    });
    Publisher.addListener('month',function(price){
        console.log('本月价格: '+price);
    });
    Publisher.addListener('week',function(num){
        console.log('本周数量: '+num);
    });
    Publisher.publish('month',123);  //手动发布消息
    //本月数量: 123
    //本月价格: 123
    Publisher.publish('week',5);
    //本周数量: 5
    

    实际应用:

    $.ajax('http://xxx.com?login',function(data){
       Publisher.publish('loginSuccess',data);  //若登录成功则向所有订阅者发布登录成功的消息
    });
    //以下在各个模块添加订阅消息
    var header = (function () {
        Publisher.addListener('loginSuccess', function (data) {
            header.setAvatar(data.avatar);
        });
        return {
            setAvatar: function (data) {
                console.log('设置header模块的头像')
            }
        }
    })();
    var nav = (function () {
        Publisher.addListener('loginSuccess', function (data) {
            nav.setAvatar(data.avatar);
        });
        return {
            setAvatar: function (avatar) {
                console.log('设置header模块的头像')
            }
        }
    })();
    //...可随意添加其他模块
    

    参考文献:
    《JavaScript模式》
    《JavaScript设计模式与开发实践》

  • 相关阅读:
    12.C语言控制窗口
    11.字符,字符常见开发,_itoa函数
    Clusterware 和 RAC 中的域名解析的配置校验和检查 (文档 ID 1945838.1)
    导致实例逐出的五大问题 (文档 ID 1526186.1)
    如何诊断 11.2 集群节点驱逐问题 (文档 ID 1674872.1)
    11gR2新特性---Gpnp守护进程
    CSS 功能简介
    11gR2新特性---gipc守护进程
    10g集群启动顺序
    11gR2集群件任务角色分离(Job Role Separation)简介
  • 原文地址:https://www.cnblogs.com/susufufu/p/5808885.html
Copyright © 2011-2022 走看看