EventEmitter

//工具函數,判斷所屬類型,判斷是不是null或者undefined
const toString = Object.prototype.toString;
const isType = obj => toString.call(obj).slice(8, -1).toLowerCase();
const isArray = obj => Array.isArray(obj) || isType(obj) === "array";
const isNullOrUndefined = obj => obj === null || obj === undefined;
/**
 * 添加事件
 * @param {*} type 監聽事件的名稱
 * @param {*} fn   監聽事件對應的方法
 * @param {*} context 改變this的指向/執行的主體
 * @param {*} once 是否只執行一次
 */
const _addListener = function(type, fn, context, once) {
  if (typeof fn != "function") {
    throw new TypeError("fn 必須是一個函數");
  }
  fn.context = context;
  fn.once = !!once;
  const event = this._events[type];
  //若是隻執行一次, this._events[type] 將是一次函數
  if (isNullOrUndefined(event)) {
    this._events[type] = fn;
  } else if (typeof event === "function") {
    //若是已經存在(監聽)一個函數,則this._events[type]將是一個數組
    this._events[type] = [event, fn];
  } else if (isArray(event)) {
    //若是存在(監聽)多個函數(數組),則push
    this._events[type].push(fn);
  }
  return this;
}

//EventEmitter類
class EventEmitter {
  constructor() {
    //初始化_events屬性
    if (isNullOrUndefined(this._events)) {    
      this._events = Object.create(null);
    }
  }
  //添加事件
  addListener(type, fn, context) {
    return _addListener.call(this, type, fn, context);
  }
  //可執行屢次
  on(type, fn, context) {
    return this.addListener(type, fn, context);
  }
  //執行一次
  once(type, fn, context) {
    return _addListener.call(this, type, fn, context, true);
  }
  //事件觸發
  emit(type, ...rest) {
    if (isNullOrUndefined(type)) {
      throw new Error("emit必須接收至少一個參數");
    }
    const events = this._events[type];
    if (isNullOrUndefined(events)) return false;
    if (typeof events === "function") {
      //用call改變this的指向指向events.context主體,不然指向null
      events.call(events.context || null, rest);
      //執行完畢判斷是否只執行一次,是則移除
      if (events.once) {
        this.removeListener(type, events);
      }
    } else if (isArray(events)) {
      events.map(e => {
        e.call(e.context || null, rest);
        if (e.once) {
          this.removeListener(type, e);
        }
      })
    }
    return true;
  }
  //事件移除
  removeListener(type, fn) {
    if (isNullOrUndefined(this._events)) return this;
    if (isNullOrUndefined(type)) return this;
    if (typeof fn !== "function") {
      throw new Error("fn 必須是一個函數");
    }
    const events = this._events[type];
    if (typeof events === "function") {
      events === fn && delete this._events[type];
    } else {
      const findIndex = events.findIndex(e => e === fn);
      if (findIndex === -1) return this;
      if (findIndex === 0) {
        events.shift();
      } else {
        events.splice(findIndex, 1);
      }
      //若是隻剩下一個監聽者,則把數組變爲函數
      if (events.length === 1) {
        this._events[type] = events[0];
      }
    }
    return this;
  }
  //刪除全部事件
  removeAllListeners(type) {
    if (isNullOrUndefined(this._events)) return this;
    //若是沒有指定type,則刪除所有
    if (isNullOrUndefined(type)) this._events = Object.create(null);
    const events = this._events[type];
    if (!isNullOrUndefined(events)) {
      //判斷是否只剩下最後一個事件
      if (Object.keys(this._events).length === 1) {
        this._events = Object.create(null);
      } else {
        delete this._events[type];
      }
    }
    return this;
  }
  //監聽隊列
  listeners(type) {
    if (isNullOrUndefined(this._events)) return [];
    const events = this._events[type];
    return isNullOrUndefined(events) ? [] : (typeof events === "function" ? [events] : events.map(o => o));
  }
  //監聽者數量
  listenerCount(type) {
    if (isNullOrUndefined(this._events)) return 0;
    const events = this._events[type];
    return isNullOrUndefined(events) ? 0 : (typeof events === "function" ? 1 : events.length);
  }
  eventNames() {
    if (isNullOrUndefined(this._events)) return [];
    return Object.keys(this._events);
  }
}

參考自https://www.php.cn/js-tutoria... 做者:php中世界最好的語言php

相關文章
相關標籤/搜索