受到 node 中的事件订阅器的启发,我感觉事件编程在某些地方很有用。尤其是解耦方面,于是乎,造轮子事件来了。
还记得前端网页是怎么注册浏览器事件的吗?
123456var a = document.createElement('a');a.addEventListener('click', function () { alert('hello, you clicked');});
其实这就是事件订阅了。因为 a
注册了 click
事件,并绑定了回调函数。当 a
被鼠标所点击的时候,这个回调函数就会被执行。
那么怎么样做一个无关平台的 javascript 事件订阅器呢?其实也挺容易的,一个完整的事件订阅器应该由这几个部分组成:
- 能注册事件
- 能删除事件
- 能产生事件并执行订阅者指定的回调函数
这几部分理清楚了就好设计了
123456789101112131415161718192021222324252627class 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)的功能。用法也还好:
12345678910111213141516const people = { name: 'vec', run(){ this.emit('run', this.name); },};/* 必须要获得这个事件订阅器的各种方法 */people.__proto__ = EventEmitter.prototype;people.on('run', name => console.log(name, '在跑步'));people.run();//vec 在跑步
当然,这个只是很简单的事件订阅器,稍微能看的应该是要支持 冒泡
和 绑定上下文
的,不过对于凑稿费和加深理解应该够用了