手写极简版EventBus

3,366 阅读1分钟

起因

在拼多多面试时,面试官问了下Vue中的组件数据传递方式,我就提到了EventBus,不过之前并没有仔细研究,当时写的版本也问题很多。因此回来之后又重新整理了下。如果有错误或者问题,希望大家可以指出来

// EventBus构造函数
function EventBus(){
  this.listeners = {} //保存已经注册的事件
}

// 判断是否为函数
function isFunction(fn) {
  return fn && Object.prototype.toString.call(fn)=== '[object Function]'
}

// 判断是否为字符串
function isString(str) {
  return str && (typeof(str) === 'string' || Object.prototype.toString.call(str)=== '[object String]')
}

function isValid(event, callback) {
    return isString(event) && isFunction(callback)
}

// 监听事件的方法
EventBus.prototype.$on = function(event, callback) {
  if (isValid(event, callback)) { //校验参数合法性
    if (this.listeners[event] && !this.listeners[event].includes(callback)) { // 已经注册过该事件的话,将callback加入到该事件的回调数组中
      this.listeners[event].push(callback)
    } else {
      this.listeners[event] = [callback] // 若之前没有监听过该事件,则初始化为一个数组
    }
  } else {
    console.error('参数不合法或已存在')
  }
}

// 触发已经注册过的事件
EventBus.prototype.$emit = function(event, params) {
  if (isString(event) && this.listeners[event]) {
    this.listeners[event].forEach(cb => { // 将该事件上所有的回调函数都执行一次
      cb(params)
    })
  }
}

// 移除某事件对应的回调函数
EventBus.prototype.$remove = function(event, callback) {
  if (isValid(event, callback) && this.listeners[event]) {
    let index = this.listeners[event].indexOf(callback)
    if (index !== -1) {
      this.listeners[event].splice(index, 1)
    }
  }
}

// demo
var eb = new EventBus()
const cb = function(params){
    console.log('add ', params)
}
eb.$on('add', cb)

eb.$emit('add', 123)
// 打印 'add 123'

eb.$remove('add', cb)
console.log(eb)
//打印
// EventBus {
//    listeners: {
//      'add': []
//    }
// }