事件订阅的编程方式

受到 node 中的事件订阅器的启发,我感觉事件编程在某些地方很有用。尤其是解耦方面,于是乎,造轮子事件来了。

还记得前端网页是怎么注册浏览器事件的吗?

var a = document.createElement('a');

a.addEventListener('click', function () {
    alert('hello, you clicked');
});

其实这就是事件订阅了。因为 a 注册了 click 事件,并绑定了回调函数。当 a 被鼠标所点击的时候,这个回调函数就会被执行。

那么怎么样做一个无关平台的 javascript 事件订阅器呢?其实也挺容易的,一个完整的事件订阅器应该由这几个部分组成:

这几部分理清楚了就好设计了

class EventEmitter {
    checkPool(name){
        if (typeof(this._evpool) !== 'object') {
            this._evpool = {}
            return this.checkPool(...arguments)
        }

        if (!Array.isArray(this._evpool[name])) {
            this._evpool[name] = []
            return this.checkPool(...arguments)
        }

        return this._evpool[name]
    }
    emit(name, ...args){
        this.checkPool(name).forEach(cb => cb(...args))
    }
    on(name, ...args){
        this.checkPool(name).push(...args)
    }
    remove(name, ...args){
        this._evpool[name] = this.checkPool(name).filter(cb => !args.includes(cb))
    }
    clear(name){ this.checkPool(name).splice(0) }
}

这个自制的事件订阅器有注册事件(on)、产生事件(emit)、删除事件函数(remove)以及移除事件所有函数(clear)的功能。用法也还好:

const people = {
    name: 'vec',
    run(){
        this.emit('run', this.name);
    },
};

/* 必须要获得这个事件订阅器的各种方法 */
people.__proto__ = EventEmitter.prototype;

people.on('run', name => console.log(name, '在跑步'));

people.run();

//vec 在跑步

当然,这个只是很简单的事件订阅器,稍微能看的应该是要支持 冒泡绑定上下文 的,不过对于凑稿费和加深理解应该够用了