自己实现一个EventMitter类

117 阅读1分钟
class EventMitter {
  private _events: Record<string, Function[]>;
  constructor() {
    this._events = Object.create(null);
  }

  on(eventName: string, fn: Function) {
    if (typeof fn !== "function") {
      throw new TypeError("The event-triggered callback must be a function");
    }

    this._events[eventName]
      ? this._events[eventName].push(fn)
      : (this._events[eventName] = [fn]);
  }

  emit(eventName: string, ...args: any[]) {
    if (!this._events[eventName]) return false;

    const fns = [...this._events[eventName]]
    fns.forEach(fn => {
      fn.apply(this, args)
    })
    return true;
  }

  once(eventName: string, fn: Function) {
    const execFn = () => {
      fn.apply(this)
      this.off(eventName, execFn)
    }

    this.on(eventName, execFn)
  }

  off(eventName: string, fn?: Function) {
    if (!this._events[eventName]) return;
    if (!fn) {
      this._events[eventName] && (this._events[eventName].length = 0)
    }

    let cb;
    let cbLen = this._events[eventName].length
    for (let i = 0; i < cbLen; i++) {
      cb = this._events[eventName][i];
      if (cb === fn) {
        this._events[eventName].splice(i, 1)
        break;
      }
    }
  }

  removeAllListeners(eventName?: string) {
    if (eventName) {
      this._events[eventName] && (this._events[eventName].length = 0)
    } else {
      this._events = Object.create(null)
    }
  }
}