一个典型的发布订阅,需要注意的两个点是
- 继承时实例属性的处理
- 绑定once时,考虑取消订阅的处理
class EventEmitter {
constructor () {
this._events = {}
}
on (name, cb) {
// 用于处理子类继承EventEmitter父类的时候,子类实例中没有_events属性的情况
// (不可能每次都需要在子类的构造函数中call一遍父类,比较麻烦)
this._events = this._events ? this._events : {}
if (this._events[name]) {
this._events[name].push(cb)
} else {
this._events[name] = [cb]
}
}
off (name, cb) {
if (this._events[name]) {
// _o是original的缩写,用于兼容once的情况。
this._events[name] = this._events[name].filter((item) => item !== cb && item._o !== cb)
}
}
once (name, cb) {
const once = (...args) => {
cb(...args)
this.off(name, once)
}
// 将原函数挂载到新once函数上,便于off取消订阅
once._o = cb
this.on(name, once)
}
emit (name, ...args) {
if (this._events[name]) {
this._events[name].forEach((item) => item(...args))
}
}
}
module.exports = EventEmitter