了解观察者模式到简单实现一个eventEmitter

759 阅读1分钟

观察者模式的简单理解:

> 就比如小时候的一个游戏“打地鼠”,我们作为观察者,地鼠是被观察者,当地鼠露出头的这个行为,我们会去做一件事情,就是去敲它。

观察者模式在前端运用的非常多,比如浏览器的事件流程、vue中的v-model,子父组件的通信,eventBus、node的内置模块events

其主要的作用是解决对象与对象之间的耦合

下面我们手动简单实现一个eventEmitter

直接上代码:

function EventEmitter () {
    this._events = new Map() // 存储事件监听的对象
    this.maxEventListener = 5 // 监听上限
}

// 添加事件监听
EventEmitter.prototype.on = function (eventType, callback) {
    const events = this._events.get(eventType)
    if (events && events.length >= this.maxEventListener) {
        throw Error('已到达事件监听数量的上限')
    }
    events || this._events.set(eventType, [])
    this._events.get(eventType).push(callback)
}

// 触发事件
EventEmitter.prototype.emit = function (eventType, ...args) {
    const events = this._events.get(eventType)
    if (events && events.length) {
        events.forEach(fn => {
            fn(...args)
        })
    }
}

// 移除监听的事件
EventEmitter.prototype.off = function (eventType, fn) {
    let events = this._events.get(eventType)
    if (!events) return false
    if (fn) { // 如果传入了fn,删除eventType对应数组里面指定的fn
        let index = events.findIndex(item => item === fn)
        if (index > -1) {
            events.splice(index, 1)
            return true
        }
        return false
    } else {//如果没有传fn,则删除_events里面的eventType
        this._events.delete(eventType)
        return true
    }
}


// 监听事件,但只触发一次
EventEmitter.prototype.once = function (eventType, callback) {
    const _this = this
    function fn () {
        callback.apply(null, [...arguments])
        _this.off(eventType, fn)
    }
    this.on(eventType, fn)
}

// 设置监听上限
EventEmitter.prototype.setMaxEventListener = function (n) {
    this.maxEventListener = n
}

const obsever = new EventEmitter()
const foo = function () {
    console.log('foo')
}
obsever.on('click', (params) => {
    console.log('触发click',params)
})
obsever.on('change', () => console.log('触发change'))
obsever.on('change', foo)
obsever.once('change', ()=>console.log('once'))
obsever.emit('click','params')
obsever.emit('change')
obsever.off('change', foo)
obsever.emit('change')

// 触发click params
// 触发change
// foo
// once
// 触发change