• JS实现发布/订阅


    JS实现发布/订阅

    最近在看面试题时,遇到了手写发布/订阅的题目,所以想写一个文档进行总结。
    大体上的思路是通过在class中创建一个存储事件及其关联函数的对象,使用on方法进行事件的存储,将传入的函数保存到相应名称的属性中;使用emit方法触发事件,执行对象中相应属性中的函数;使用remove方法移除事件,移除相应属性中的函数或直接移除相应属性。

    class MyEvent {
      constructor() {
        this.eventList = {};//创建事件对象,每个属性都是一个数组,可以存放多个函数
      }
      on(name, fn) {//创建/添加事件
        if (!this.eventList[name]) {
          this.eventList[name] = [];//如果没有该事件,就创建并初始化该事件
        }
        if (typeof fn !== "function") throw new Error("缺少回掉函数");
        this.eventList[name].push(fn);//将回掉函数添加到该事件的函数队列中去
      }
      emit(name, ...param) {//触发事件
        if (!this.eventList[name]) {//如果不存在该事件的话就报错
          throw new Error(`未知事件${name}`);
        }
        this.eventList[name].forEach((fn) => {//否则就挨个执行该事件中的函数,并将参数传进去
          fn(...param);
        });
      }
      remove(name, fn) {//移除事件
        if (!this.eventList[name]) {//如果不存在该事件的话就报错
          throw new Error(`未知事件${name}`);
        }
        if (!fn) {//如果没有传第二个参数则默认删除该事件
          delete this.eventList[name];
        } else if (typeof fn !== "function") throw new Error("函数错误");//如果传入类型错误则报错
        else {
          const index = this.eventList[name].indexOf(fn);//查找函数在该事件函数队列中的下标
          if (index === -1) throw new Error("未找到函数");//如果没找到就报错
          this.eventList[name].splice(index, 1);//找到了就删除该函数
          if (this.eventList[name].length === 0) delete this.eventList[name];//如果该事件的函数队列为空,则删除该事件
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在使用时可以通过new来创建实例,调用其中的方法进行发布/订阅。

    const callbackfunc1 = (a) => {
      console.log("触发事件", a);
    };
    const callbackfunc2 = () => {
      console.log("触发事件2");
    };
    let eventTest = new MyEvent();
    eventTest.on("event1", callbackfunc2);
    eventTest.emit("event1", 11111);
    eventTest.remove("event1", callbackfunc1);
    eventTest.emit("event1", 11111);
    eventTest.remove("event1");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    需要注意的是,如果事件绑定的函数之后可能要被移除,那么该函数要提前定义好。如果在传入的时候再进行定义,移除时使用indexOf()方法会找不到该函数,因为在使用on创建和使用remove移除时,对程序来说传入的实际上是两个不同的函数:

    eventTest.on("event1", (a) => {
      console.log("触发事件", a);
    });
    eventTest.emit("event1", 11111);
    eventTest.remove("event1", (a) => {//这里会报错,找不到函数
      console.log("触发事件", a);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符
  • 相关阅读:
    java-php-python-ssm-学校图书资源交易平台-计算机毕业设计
    C++实现哈希表。
    欧盟电动助力自行车标准EN15194
    LeetCode每日一题(911. Online Election)
    Go map作为函数参数 (引用传递,修改形参会影响到实参)
    “自主可控”的正确姿势—自主可控交换机的机遇与挑战
    监控画面时间同步校准
    【kali-Metasploit】Armitage常见问题:sudo权限、连接不到数据库、service not found
    云计算 - 弹性计算技术全解与实践
    聚苯乙烯/Fe3O4纳米复合材料PS@Fe3O4|硫化锌-四氧化三铁(ZnS/Fe3O40纳米复合物(齐岳)
  • 原文地址:https://blog.csdn.net/GCWsuger/article/details/126910623