手寫發佈訂閱模式 EventEmitter
1.簡介
最近發現好多大廠面試題裏都有手寫發佈訂閱模式 EventEmitter,原因是 vue 和 react 的非父子組件的通信就是靠他實現的,下面是一個簡易版的 EventEmitter。
2.代碼
// 發佈訂閱模式
class EventEmitter {
constructor() {
// 事件對象,存放訂閱的名字和事件 如: { click: [ handle1, handle2 ] }
this.events = {}
}
// 訂閱事件的方法
on(eventName, callback) {
if (!this.events[eventName]) {
// 一個名字可以訂閱多個事件函數
this.events[eventName] = [callback]
} else {
// 存在則push到指定數組的尾部保存
this.events[eventName].push(callback)
}
}
// 觸發事件的方法
emit(eventName, ...rest) {
// 遍歷執行所有訂閱的事件
this.events[eventName] &&
this.events[eventName].forEach(f => f.apply(this, rest))
}
// 移除訂閱事件
remove(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(f => f != callback)
}
}
// 只執行一次訂閱的事件,然後移除
once(eventName, callback) {
// 綁定的時fn, 執行的時候會觸發fn函數
const fn = () => {
callback() // fn函數中調用原有的callback
this.remove(eventName, fn) // 刪除fn, 再次執行的時候之後執行一次
}
this.on(eventName, fn)
}
}
3.使用
const event = new EventEmitter()
const handle = (...pyload) => console.log(pyload)
event.on('click', handle)
event.emit('click', 100, 200, 300, 100)
event.remove('click', handle)
event.once('dbclick', function() {
console.log('click')
})
event.emit('dbclick', 100)
參考鏈接