JS中的发布订阅

JS中的发布订阅设计模式

基于单例设计模式构建发布订阅(对象)

/* 
 * 设计模式:是一种思想,用来有效管理代码的思想
     + 单例设计模式:对象
     + 工厂设计模式:面向对象创建实例
     + Promise设计模式:异步管理
     + 发布订阅设计模式
     + ...

  发布订阅:
    来源于 DOM2级事件池
    
  DOM2级事件池机制:可以同时给同一事件类型行为绑定多个方法,当事件触发,绑定的方法依次被执行
*/

 function dom1(){
  console.log('dom1');
}
function dom2(){
  console.log('dom2');
}
function dom3(){
  console.log('dom3')
}
// DOM2级事件绑定(添加方法:指定事件类型和方法)
document.body.addEventListener('click', dom1);
document.body.addEventListener('click', dom2);
document.body.addEventListener('click', dom3);
// 移除方法(指定要移除的事件类型和方法)
document.body.removeEventListener('click', dom2); 

/* 
 * 事件池机制:
      有一个池子,可以往里面添加和删除方法,当指定行为触发,其绑定的方法依次被执行
      事件池结构设计:
      + 数组中放对象,且每个对象只存事件类型和函数
        [{type: xxx, func: yyy}, {type: xxx, func: yyy}, ...]
      + 对象:键key为事件类型,值为事件类型绑定的方法(通常是一个数组)
        {AA:[xx1, xx2,...], BB:[yy1,yy1,...],...}
*/

let sub = (function(){
  let eventPool = {};
// 往事件池中添加事件
function on(type, fun){
  // debugger;
  let funs = eventPool[type] || [];
  // console.log(funs.length);
  // 判断同一类型中该事件是否已经存在
  for(let i=0; i<funs.length; i++){
    if(funs[i] === fun) return;
  }
  funs.push(fun);
  eventPool[type] = funs;
}

// 往事件中删除方法
function off(type, fun){
  let arr = eventPool[type] || [];
  // console.log(arr);
  if(arr<=0) return;
  for(let i=0; i< arr.length; i++) {
    if(arr[i] === fun) {
      arr.splice(i,1); // 注意数组塌陷问题
      break; // 添加break是阻断数组继续往下查找,以为已经找到了
    }
  }
}

// 通知事件池中执行行为的方法执行
function fire(type, ...params) {
  let arr = eventPool[type]; 
  arr = arr.slice(0);
  console.log(arr); 
  // 命令式编程
  for(let i=0; i<arr.length; i++) {
    let item = arr[i];
    item(...params);
  }
  // 函数式编程
  // arr.forEach(item =>item(...param));
}

return {
  on,
  off,
  fire
}
})();

function f1(){
  console.log(1);
}
function f2(){
  sub.off('aa', f2);
  console.log(2);
}
function f3(){
  console.log(3);
}
sub.on('aa',f1);
sub.on('aa',f2);
sub.on('aa',f3);
document.body.onclick = function(){
  sub.fire('aa'); 
}

基于工厂模式构建发布订阅(构建函数)

(function(){
  function Sub(){
   return new init();
  }
  // 仿照JQ实现执行函数就可以创建其实例
  function init(){
    this.eventPool = {};
  }
  Sub.prototype = {
    constructor: Sub,
    add(type, fn){
      !this.eventPool.hasOwnProperty(type) ? this.eventPool[type] = [] : null;
      let arr = this.eventPool[type];
      if(arr.includes(fn)) return;
      arr.push(fn)
    },
    remove(type, fn){
      let arr = this.eventPool[type];
      if(!arr) return;
      arr = arr.filter(item => item !== fn);
      this.eventPool[type] = arr;

    },
    done(type, ...param){
      let arr = this.eventPool[type];
      if(!arr) return;
      arr.forEach(item => {
        item(...param)
      });
    }
  };

  init.prototype = Sub.prototype;
  window.Sub = Sub;
})();
let s1 = Sub();
function f1(){
  console.log(1);
}
function f2(){
  console.log(2)
}
s1.add('aa', fn1);
s1.add('aa', fn2);

function dom1(){
  s1.remove('aa', fn1);
  console.log('dom1');
}
s1.add('aa', dom1);
document.body.onclick = function(){
  s1.done('aa');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值