SOURCE

class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(key, fn) {
        if (!key || !fn) {
            return;
        }
        if (this.events[key]) {
            this.events[key].push(fn);
        }
        else {
            this.events[key] = [fn];
        }
    }

    once(key, fn) {
        if (!key || !fn) {
            return;
        }
        const func = function() {
            fn.call(this, ...arguments);
            this.off(key, func);
        };
        this.on(key, func);
    }

    emit(key, ...rest) {
        this.events[key] && this.events[key].forEach(fn => {
            fn.apply(this, rest);
        });
    }

    off(key, fn) {
        if (!this.events[key]) {
            return;
        }
        if (fn) {
            this.events[key] = this.events[key].filter(item => item !== fn);
        }
        else {
            this.events[key] = [];
        }
    }
}

const emitter = new EventEmitter();

emitter.on('a', () => console.log(1))
emitter.on('a', () => console.log(2))
emitter.on('a', () => console.log(3))

emitter.emit('a')
emitter.emit('a')
emitter.off('a')
emitter.emit('a')


emitter.once('b', (num) => console.log('haha' + num))
emitter.once('b', () => console.log('hehe'))

emitter.emit('b', 99)
emitter.emit('b')
console 命令行工具 X clear

                    
>
console