前端面试题系列之手写EventBus自定义事件

251 阅读1分钟
实现以下功能:
    1. on 多次绑定,即可以多次执行,直到被off掉
    2. once  一次绑定,即只能执行一次便自动off掉,或未执行也可以被off掉
    3. emit 触发事件,且能够传入参数
    4. off 取消事件

分析:
    1. on和once注册函数,并存储起来,按照注册顺序依次执行
    2. emit时找到对应的函数并执行
    3. off找到对应的函数,并从对象中删除
    
class EventBus {
    // 初始化
    constructor(){
        this.bus = {}
    }
    
    on(type, fn, isOnce = false) {
        const bus = this.bus
        if(bus[type] == null) bus[type] = [] // 如果该类型不存在,则定义
        bus[type].push({ fn, isOnce }) // 将该事件注册到该类型中
    }
    once(type,fn) {
        // 做法类似与on,所以直接调用即可,isOnce是用来区分的
        this.on(type,fn,true)
    }
    off(type, fn) {
        const fnList = this.bus[type] // 拿到该类型下的所有事件
        if (fnList == null || !fnList.length) return; // 当该类型没有事件或没有该类型时直接返回
        if(!fn) {
            // 没有传入fn,则off掉该类型的所有注册事件
            this.bus[type] = []
        } else {
            this.bus[type] = this.bus[type].filter(item => item.fn !== fn)
        }
    }
    emit(type,...arg){
        const fnList = this.bus[type] // 拿到该类型下的所有事件
        if (fnList == null || !fnList.length) return; // 当该类型没有事件或没有该类型时直接返回
        
        this.bus[type] = fnList.filter(item => {
            // 执行事件
            const {fn,isOnce} = item
            fn(...arg)
            
            // 用来区分是否为once,如果是once,则执行完后过滤掉,不返回
            if(!isOnce) return true
            return false
        })
    }
}

测试代码:
const fn1 = (a,b,c) => console.log(`1 ${a} ${b} ${c}`)
const fn2 = (a,b,c) => console.log(`2 ${a} ${b} ${c}`)
const fn3 = (a,b,c) => console.log(`3 ${a} ${b} ${c}`)
const fn4 = (a,b,c) => console.log(`4 ${a} ${b} ${c}`)

const bus = new EventBus()
bus.on('key', fn1)
bus.on('key', fn2)
bus.once('key', fn3)
bus.on('key', fn4)

bus.emit('key', 'a','b','c')
bus.emit('key','a','b','c')
bus.off('key', fn2)
bus.emit('key', 'a','b','c')

查看输出结果,非常简单了

12.png