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];//如果该事件的函数队列为空,则删除该事件
    }
  }
}

在使用时可以通过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");

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

eventTest.on("event1", (a) => {
  console.log("触发事件", a);
});
eventTest.emit("event1", 11111);
eventTest.remove("event1", (a) => {//这里会报错,找不到函数
  console.log("触发事件", a);
});
标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符 标题复制10行,并且每行大于10个字符
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值