请实现一个 EventMitter 类?

class EventEmitter {
  constructor(options = {}) {
    this._events = {};
    const DEFAULT_MAX_LISTENER = 10;
    this._maxListener = options.maxListener
      ? options.maxListener
      : DEFAULT_MAX_LISTENER;
  }

  on(type, listener) {
    if (this._events[type]) {
      this._events[type].push(listener);
      if (
        this._maxListener !== 0 &&
        this._events[type].length > this._maxListener
      ) {
        throw new RangeError("超过最大事件数量" + this._maxListener);
      }
    } else {
      this._events[type] = [listener];
    }
  }

  once(type, listener) {
    const self = this;
    function onceTime(...args) {
      listener.call(self, ...args);
      self.off(type, onceTime);
    }

    this.on(type, onceTime);
  }

  off(type, listener) {
    if (!listener) {
      throw new Error("listener is required");
    }
    if (this._events[type]) {
      const index = this._events[type].indexOf(listener);
      if (index >= 0) {
        this._events[type].splice(index, 1);
      }
    }
  }

  removeAll(type) {
    if (this._events[type]) {
      this._events[type] = [];
    }
  }

  emit(type, ...args) {
    if (this._events[type]) {
      this._events[type].forEach((fn) => fn.call(this, ...args));
    }
  }
}

const event = new EventEmitter({ maxListener: 3 });
console.log(event);

// 匿名函数直接传入是无法被 off 的
event.on("test1", (params) => console.log(params, "-----"));
event.on("test1", (params) => console.log(params, "-----"));

event.off("test1");

event.emit("test1");

See the Pen JS 编程题 – 请实现一个 EventEmitter 类? by hjoker (@hjoker) on CodePen.