发布订阅是一种设计模式,基于事件池机制完成

    • @1 往事件池中添加事件 on [去重机制]
    • @2 从事件池中拿出事件来执行,fire(emit)

    • @3 从事件池中移除事件off/remove

    image.png

    • 事件池这个对象可以有两种数据结构:

      1. @1.是个数组,数组中的每一项是个对象,对象存储事件标志和事件方法<br /> @2.是个对象,事件标记作为属性名,属性值是个数组,数组存储所有方法
    • 三个方法:

      @1.订阅(增加方法)on
      先判断事件池中有没有当前事件标志,没有就创建;有的话判断有没有绑定过这个方法,没有绑定的话再绑定(完成了去重)
      @2.发布(执行方法)fire
      第一参数是事件标志,后面所有参数是给执行方法传参
      拿到传参的事件标志,把其中所有的方法强制改变this,并传参执行
      @3.取消订阅(移除方法)off
      把某个事件标志中的某个方法移除 ```javascript class subsscibe{ list={}; // on 是往事件池中添加事件 on(tag,fn){

       //先判断事件池中有没有相关属性,如果没有需要赋值一个空数组
       if(!this.list.hasOwnProperty(tag)){
           this.list[tag]=[];
       };
       // 判断数组中有没有当前方法
       if(this.list[tag].includes(fn)) return;
       // 往数组中添加方法  
       this.list[tag].push(fn);
      

      }; //off 是从事件池中移除事件 off(tag,fn){

       // 如果当前事件类型存在
       if(this.list[tag]){
           // 拿到当前索引
           let index=this.list[tag].indexOf(fn);
           if(index>-1){
               // 当索引大于-1 就把这一项删除
               this.list[tag].splice(index,1);
           }
       };
      

      }; //把事件池中的函数拿出来执行 fire(tag,…params){

       if(this.list[tag]){
           this.list[tag].forEach(fn=>{
               // 拿到事件池中的每一个方法 改变this执行并传参执行 fn()=>this window  所以要改变this的指向
               fn.call(this,...params);
           });
       }
      

      }; };

    //=============如何用

    let sub=new subsscibe(); //此时方法中的this为sub实例对象

    function eat1(food){ console.log(吃:${food}); }; function drink(){ console.log(‘喝水了’); }; //对比addEventListener/removeEventListener 采用了事件池

    // 第一个参数是事件标记,是表示不同函数的作用 sub.on(‘eat’,eat1); sub.on(‘drink’,drink); // 执行函数 并传参 sub.fire(‘eat’,’汉堡包’); sub.fire(‘drink’);

    // 把eat标志的eat1方法移除 sub.off(‘eat’,eat1);

    function review(str) { console.log(‘复习’+str); } //setTimeout 异步 setTimeout(() =>{ sub.on(‘review’,review); sub.fire(‘review’,’js’) sub.fire(‘review’,’vue’) sub.fire(‘review’,’react’) });

    $(document).on(‘click’,function(){});//jq on 就运用了发布订阅机制 ```