自定义事件类主要有四个方法,分别为on、once、off、emit。这里咱们采用class语法来实现:数组
class结构:app
class EventEmitter {
constructor () {
this.events = {}
}
on (event, cb) {
return this
}
off (event, cb) {
return this
},
once (event, cb) {
return this
},
emit (event, ...args) {
return this
}
}
复制代码
events
是一个对象,用来存储事件名以及对应的回调函数;return this
返回该实例,能够链式调用。函数
on的实现:测试
on (event, cb) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(cb)
return this
}
复制代码
首先判断该event是否存在,若不存在则初始化为空数组(由于一个事件能够屡次注册,可能会对应多个方法,因此这里使用数组存储函数),而后将函数添加进去;若event存在则直接添加到该事件的函数列表中。ui
若是对可读性要求不高,可写成:this
on (event, cb) {
(this.events[event] || this.events[event] = []).push(cb)
return this
}
复制代码
off的实现:spa
off (event, cb) {
if (!cb) {
this.events[event] = null
} else {
this.events[event].some((fn, i) => {
if (cb === fn) {
this.events[event].splice(i, 1)
return true
}
})
}
return this
}
复制代码
首先判断是否有cb参数,即具体的函数,若是没有则将整个event清空,若是有则将对应的fn清除,这里只清除第一个,若是须要清除所有能够使用forEach,不终止循环。code
once的实现:对象
once (event, cb) {
const func = (...args) => {
this.off(event, func)
cb.apply(this, args)
}
this.on(event, func)
return this
}
复制代码
在内部定义一个函数,该函数只会执行一次,执行完后当即清除,即调用off方法,而后调用cb,即该事件注册时对应的方法。事件
emit的实现:
emit (event, ...args) {
const cbs = this.events[event]
if (!cbs) {
throw new Error(`${event} event is not registered.`)
}
cbs.forEach(cb => cb.apply(this, args))
return this
}
复制代码
首先判断是否注册该事件,未注册则报错,若是注册了则执行该函数
测试
const add = (a, b) => console.log(a + b)
const log = (...args) => console.log(...args)
const event = new EventEmitter()
event.on('add', add)
event.on('log', log)
event.emit('add', 1, 2) // 3
event.emit('log', 'hi~') // 'hi~'
event.off('add')
event.emit('add', 1, 2) // Error: add event is not registered.
event.once('once', add)
event.emit('once', 1, 2) // 3
event.emit('once', 1, 2)
event.emit('once', 1, 2)
复制代码
这里是简易自定义事件类的实现,你们可根据自我需求进行完善。