手写一个发布订阅(EventEmitter)

1. 直接贴代码

class EventEmitter {
  constructor() {
    this.events = {};
  }

  // 一个事件可能跟有多个订阅者,所以这里使用数组
  events: Record<string, Function[]>

  on(eventName: string, func: Function) {
    const eventsArr = this.events[eventName];
    if (eventsArr) {
      eventsArr.push(func);
    } else {
      this.events[eventName] = [func];
    }

    return this;
  }

  off(eventName: string, func: Function) {
    const eventsArr = this.events[eventName];
    if (eventsArr) {
      const funcIndex = eventsArr.findIndex(ef => ef === func);
      eventsArr.splice(funcIndex, 1);
    }

    // 释放内存
    if(eventsArr.length===0) {
      delete this.events[eventName];
    }

    return this;
  }

  once(eventName: string, func: Function) {
    // 取消订阅自己,然后执行绑定的函数
    const onThenOff = () => {
      this.off(eventName, onThenOff);
      func.apply(this, arguments)
    }
    // 订阅自己
    this.on(eventName, onThenOff);

    return this;
  }

  emit(eventName: string, ...args: any[]) {
    const eventsArr = this.events[eventName] ?? [];
    for (const event of eventsArr) {
      event.apply(this, args);
    }

    return this;
  }

  printEvents() {
    console.log(this.events);
    return this;
  }
}
////////  TEST  /////////
const hello = function () {
  console.log('hello')
}

const emitter = new EventEmitter();

emitter
  .on('hello', hello)
  .emit('hello') // 打印 hello
  .once('nihao', function () {
    console.log('nihao')
  })
  .emit('hello') // 打印 hello
  .emit('nihao') // 打印 nihao
  .emit('nihao') // 不会打印
  .off('hello', hello)
  .emit('hello') // 不会打印

2.结果

image

posted @ 2023-03-04 13:41  pangqianjin  阅读(48)  评论(0编辑  收藏  举报