• 观察者模式之ES6实现(二)


    一、问题描述
    实现一个EventEmitter类,这个类包含以下方法:
    on(监听事件,该事件可以被触发多次)
    once(也是监听事件,但只能被触发一次)
    fire(触发指定的事件)
    off(移除指定事件的某个回调方法或者所有回调方法)

    class EventEmitter {
      /**请补充你的代码***/
    }
    const event = new EventEmitter()
    const drink = (person) => {
      console.log(person + '喝水')
    }
    event.on('drink', drink)
    event.on('eat', (person) => {
      console.log(person + '吃东西')
    })
    event.once('buy', (person) => {
      console.log(person + '买东西')
    })
    event.fire('drink', '我')   // 我喝水  
    event.fire('drink', '我')   // 我喝水  
    event.fire('eat', '其它人')   // 其它人吃东西
    event.fire('eat', '其它人')   // 其它人吃东西
    event.fire('buy', '其它人')  //其它人买东西
    event.fire('buy', '其它人')  //这里不会再次触发buy事件,因为once只能触发一次
    event.off('eat')  //移除eat事件
    event.fire('eat', '其它人')  //这里不会触发eat事件,因为已经移除了

    二、问题分析
    这题其实就是实现发布-订阅模式了,难点在于怎样实现once事件,即只触发一次。其实也就是要实现两种类型的事件,我们可以用不同的对象去保存这两种类型的事件,然后在fire的时候,这两种事件都要被处理即可。

    三、参考链接

    https://github.com/Olical/EventEmitter

    四、解决方案

    class EventEmitter {
        constructor() {
            this.queue = {} //可触发多次的事件
            this.onceQueue = {} //只能触发一次的事件
        }
        on(event, fn) {  //监听事件,可以触发多次
            if (!this.queue[event]) this.queue[event] = []
            this.queue[event].push(fn)
        }
        once(event, fn) {   //监听事件,只能触发一次
            if (!this.onceQueue[event]) {
                this.onceQueue[event] = {
                    fns: [],
                    hasFired: false
                }
            }
            this.onceQueue[event].fns.push(fn)
        }
        fire() {  //触发指定的事件
            const event = [].shift.call(arguments), //取得事件名称
                fns = this.queue[event],  //取得该事件里所有的回调函数(可以触发多次的事件)
                onceFns = this.onceQueue[event]  //取得该事件里所有的回调函数(只能触发一次的事件)
            if (fns && fns.length != 0) {
    for (let item of fns) { item.apply(this, arguments) } } if (onceFns && !onceFns.hasFired) {
    for (let item of onceFns.fns) { item.apply(this, arguments) } this.onceQueue[event].hasFired = true } } off(event, fn = null) { //可移除特定事件里的某个回调函数或者所有回调函数 const fns = this.queue[event] if (!fns || fns.length == 0) return if (fn) { //移除该事件特定的回调 this.queue[event] = fns.filter(item => { return item !== fn }) } else { //移除该事件所有的回调 this.queue[event] = [] } } }
  • 相关阅读:
    vim内外部鼠标复制 粘贴
    nginx 问题解决nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    Installation of the latest version of netease-cloud-music on Fedora 30 linux platform
    Linux就该这么学11学习笔记
    Linux就该这么学10学习笔记
    css day2
    Linux就该这么学09学习笔记
    Linux就该这么学08学习笔记
    css day1
    Linux就该这么学07学习笔记
  • 原文地址:https://www.cnblogs.com/camille666/p/pub_sub_design_pattern_2.html
Copyright © 2020-2023  润新知