前言事件在js中非常常见,无论是浏览器还是节点,这种事件发布/订阅模式的应用都是非常普遍的。至于发布/订阅模式和观察者模式是不是同一种设计模式,这里不做具体讨论。在之前的项目中,我也自己实现了一个事件模块,核心是一个EventEmitter。下面将结合node中的事件模块来分析一个EventEmitter应该如何实现以及需要注意哪些点。源码地址https://github.com/nodejs/nod...基本结构和设计第一步是一个EventEmitter类,然后再考虑这个类的实例属性和实例方法。最基本的实例属性是一个eventMap,它可以是一个空对象,当然Object.create(null)也可以这样创建。如有必要,还可以添加maxListener等属性。在实例方法的情况下,核心是adddeleteemit来添加事件、删除事件和释放事件。当然,在实际实现中,比如count,has,once(一次性加),preAdd(在事件队列最前面加),这些方法可以根据实际需要添加。具体实现及注意点以下代码为简化伪代码addmethodEventEmitter.prototype.add=function(type,fn){if(!isFunction(fn))return;//判断监听中的add是否合法Function//判断是否添加了类型,一个或多个函数Unshift可以是this.event[type].push(fn);}else{//如果要实现preadd改变顺序this.event[type]=[this.event[type],fn];}}else{这个.event[type]=fn;}}once方法参考node的once方法函数this.fired=true;Reflect.apply(this.listener,this.target,args);}}function_onceWrap(target,type,listener){varstate={fired:false,wrapFn:undefined,target,type,listener};varwrapped=onceWrapper.bind(state);wrapped.listener=监听器;state.wrapFn=包裹;returnwrapped;}EventEmitter.prototype.once=functiononce(type,listener){这个.on(type,_onceWrap(this,type,listener));返回这个;};函数用onceWrap包裹,添加的monitor需要在运行前移除。删除非常简单。了解几个边界条件就足够了。EventEmitter.prototype.delete=function(type,fn){//直接删除整个监听类if(fn===undefined){this.events[type]&&deletethis.events[type];}else{//判断fn的合法性saveif(this.events[type]){if(this.events[type]===fn){deletethis.events[type];}else{for(variinthis.events[type]){if(this.events[type][i]===fn){if(i===0){this.events[type].shift();}else{this.events[type].splice(i,1);}}}if(this.events[type].length===1)this.events[type]=this.events[type][0];}}}}emitEventEmitter.prototype.emit=function(type){//获取参数varargs=[].slice.call(arguments,1);varhandler=事件[类型];如果(处理程序===未定义)返回假;if(typeofhandler==='function'){handle.apply(this,args);}else{varlen=处理程序。长度;constlisteners=arrayClone(handler,len);对于(vari=0;i
