前言
    几天前不是谈到了事件总线eventBus吗, 然后对里面的监听器相关知识挺感兴趣。今天我用代码简单实现了下,大家可以看看是否有需要改进的地方。可以跳转到本文文末查看我的最终代码。
要求
 实现一个监听器对象Listener类,需要具有四个方法:
- on(event: String, fn: Function([data[, callback])])对事件- event绑定一个监听器- fn
- once(event: String, fn: Function)对事件- event绑定一个只执行一次的监听器- fn
- off(event: String [, fn: Function] )- 只有第一个参数时,对事件event解绑所有监听器
- 有两个参数时,  对事件event解绑一个监听器fn(这里的fn需要与之前使用on函数绑定的fn指向同一个对象, 所以注意使用匿名函数做监听器函数的情况 参考eventBus一节中提到的匿名函数问题)
 
- 只有第一个参数时,对事件
- trigger(event: String, data: Object, callback: Function)触发事件- event绑定的所有监听器,并传递参数- data及回调函数- callback(回调函数需要在- on绑定的函数- fn中自定义执行位置)
思路及代码
    准备用一个Map来维护事件名与监听器列表的对应关系。
    注意在off函数中有两种参数形式,以及在trigger函数中注意移除一次性的监听器函数,代码如下:
// 判断是否为函数
function isFunction(fn) {
  return typeof fn === 'function'
}
// 监听器类
function Listener() {
  // 监听器Map, 维护事件名与监听器列表的对应关系
  this.map = new Map();
  /**
   * 添加一个监听器
   * (并没有去重,相同的监听器函数可多次添加)
   * @param {string} name 事件名
   * @param {function} fn 监听器函数
   */
  this.on = function (name, fn) {
    if (isFunction(fn)) {
      const item = { once: false, fn };
      this.map.set(name, this.map.has(name) ? this.map.get(name).push(item) : [item]);
    } else {
      throw new Error('请绑定函数')
    }
  }
  /**
   * 添加一个只执行一次的监听器
   * @param {string} name 事件名
   * @param {function} fn 监听器函数
   */
  this.once = function (name, fn) {
    if (isFunction(fn)) {
      const item = { once: true, fn };
      this.map.set(name, this.map.has(name) ? this.map.get(name).push(item) : [item]);
    } else {
      throw new Error('请绑定函数')
    }
  }
  /**
   * 移除监听器
   * 若无第二个参数fn, 则移除所有监听器
   * @param {string} name 事件名
   * @param {function} fn 监听器函数
   */
  this.off = function (name, fn) {
    if (this.map.has(name)) {
      if (!fn) {
        this.map.delete(name);
      } else if (isFunction(fn)) {
        let items = this.map.get(name);
        let index = items.findIndex(item => item.fn === fn);
        if (index > -1) {
          items.splice(index, 1);
        }
      } else {
        throw new Error('请解绑函数')
      }
    }
  }
  /**
   * 触发监听器
   * @param {string} name 事件名
   * @param {object} data 传递参数
   * @param {function} callback 回调函数
   */
  this.trigger = function (name, data, callback) {
    if (this.map.has(name)) {
      let items = this.map.get(name);
      for (let len = items.length, i = len - 1; i >= 0; i--) {
        let { once, fn } = items[i];
        fn(data, callback);
        if (once) {
          items.splice(i, 1); // 移除只执行一次的监听器
        }
      }
    }
  }
}
// 测试
let l = new Listener();
l.on('event1', (data) => { // 每次使用trigger函数触发都会执行一次
  console.log('event1 on', data);
})
// l.once('event1', (data) => { // 只执行一次,之后不再执行(已被移除)
//  console.log('event1 once', data);
// })
l.trigger('event1', 1) // event1 1
l.trigger('event1', 2) // 不执行
l.trigger('event1', 3) // 不执行
let fn = (data, callback) => { // 定义监听器函数fn
  console.log(data);
  callback(data);
}
l.on('event2', fn)
console.log(l, l.map);
l.trigger('event2', 1, (res) => { // 传入数据 1, 并执行回调函数
  console.log('callback1', res * 2); // callback1 2
})
l.off('event2', fn); // 移除事件‘event2’提仅有的监听器函数fn, 所以之后的trigger函数无法正确执行
l.trigger('event2', 2, (res) => { // 传入数据 2, 并执行回调函数
  console.log('callback2', res * 3); // callback1 6
})
console.log(l, l.map); 
                     
                     
                        
                        