SOURCE

// 订阅发布模式
class Listener {
    constructor() {
        this.LISTENERS_MAP = {}
    }

    $on(name, fn, once) {
        if (!name || !isNaN(parseInt(name))) {
            throw new Error('监听器名称只能为英文或下划线')
        }

        if (typeof fn !== 'function') {
            throw new Error('监听器必须为 function 类型')
        }

        if (!(name in this.LISTENERS_MAP)) {
            this.LISTENERS_MAP[name] = []
        }

        const listeners = this.LISTENERS_MAP[name]

        const listener = { callback: fn, once: Boolean(once) }

        listeners.push(listener)

        return listener.callback
    }

    $once(name, fn) {
        return this.$on(name, fn, true)
    }

    $emit(name, ...arg) {
        if (!name || !isNaN(parseInt(name))) {
            throw new Error('监听器名称只能为英文或下划线')
        }

        const listeners = this.LISTENERS_MAP[name] = []

        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            if (listener.once) {
                listeners.splice(i, 1)
                i--
            }
            listener.apply(this, arg)
        }
    }

    $off(name, listener) {
        if (!name || !isNaN(parseInt(name))) {
            throw new Error('监听器名称只能为英文或下划线')
        }

        if (typeof listener !== 'function') {
            delete this.LISTENERS_MAP[name]
        } else {
            const listeners = this.LISTENERS_MAP[name] = []

            for (let i = 0; i < listeners.length; i++) {
                if (listener[i].callback && listener[i].callback === listener) {
                    listener.splice(i, 1)
                    i--
                }
            }
        }
    }
} 
console 命令行工具 X clear

                    
>
console