#36 实现一个 EventEmitter


  • 0

    class EventEmitter {
      /* TODO */
      constructor(){
        this.store = []; 
        this.fns = {};
      }
      on(eventName, func){
        this.fns[eventName] = func;
        this.store.push(this.fns);
        this.fns = {};
      }
      emit(eventName, ...props){
        this.store.forEach( (fns) => {
          if(fns[eventName]) fns[eventName](...props);
        })
      }
      off(eventName, func){
        this.store.forEach( (fns, index) => {
          if(fns[eventName] === func){
            this.store.splice(index, 1);
            return false;
          }
        })
      }
    }
    

  • 0

    class EventEmitter {
        /* TODO */
        constructor() {
    
            this.events = {};
        }
    
        on(type, fun) {
            if(!this.events.hasOwnProperty(type)){
                 this.events[type] = [];
            }
            this.events[type].push(fun);
        }
        off(type,fun){
            let funs = this.events[type];
            if(!funs || funs.length < 1){
                return false;
            }
            if(!fun){
                return delete this.events[type];
            }
            if(funs.includes(fun)){
                const index = funs.indexOf(fun);
                funs.splice(index,1);
            }
            if(funs.length < 0){
                return delete this.events[type];
            }
            this.events[type] = funs;
    
        }
        emit(){
            let type = arguments[0],arg = [];
            for(let i =1;i<arguments.length;i++){
                arg.push(arguments[i]);
            }
            let funs = this.events[type];
            if(!funs || funs.length < 1){
                return false;
            }
            funs.forEach(fun => {
                fun.apply(this,arg);
            });
        }
    }
    

  • 0

    @jason94
    Array.prototype.shift.call(arguments),这个用的好,我还是自己循环取了一遍


  • 0

    我参照大家给出的比较好的代码
    
    class EventEmitter {
      constructor(){
        this.events={}
      }
      /* TODO */
      on(e,f) {
        const callback = this.events[e]||[]
        callback.push(f)
        this.events[e] = callback
      }
      emit(e,...params) {
        if(this.events.hasOwnProperty(e)) {
          const callbacks = this.events[e]
          callbacks.map((f)=>{
            f(...params)
          })
        }
      }
      off(e,f) {
            if(this.events.hasOwnProperty(e)) {
          const callbacks = this.events[e]
          if(callbacks.includes(f)) {
            let index = callbacks.indexOf(f)
            callbacks.splice(index,1)
          }
        }
      }
    }
    

  • 0

    为啥感觉虽然写对了却稀里糊涂的就对了。。。。。

    class EventEmitter {
      constructor (){
        this.listenerobj = {};
      }
    
      on (funcname, listener){
        if(!this.listenerobj[funcname]){
          this.listenerobj[funcname] = [];
        }
        this.listenerobj[funcname].push(listener);
      }
      emit (funcname, ...args){
        this.listenerobj[funcname].forEach((item, idx) => {
          item(...args);
        });
      }
      off (funcname, targetlistener){
        this.listenerobj[funcname].splice(this.listenerobj[funcname].indexOf(targetlistener),1);
      }
    }
    
    

  • 0

    感觉这个练习把题目做出来并不难,主要是为了通过这道题熟悉观察者模式的套路和实现方式。怎样完美地解耦等等。

    class EventEmitter {
      constructor (){
        this.listenerobj = {};
      }
    
      on (funcname, listener){
        this.listenerobj[funcname] = this.listenerobj[funcname] || [];
        this.listenerobj[funcname].push(listener);
      }
      emit (funcname, ...args){
        this.listenerobj[funcname].forEach((item, idx) => {
          item(...args);
        });
      }
      off (funcname, targetlistener){
        this.listenerobj[funcname].splice(this.listenerobj[funcname].indexOf(targetlistener),1);
      }
    }
    
    

  • 0

    @ScriptOJ 新手想请教一下这个为啥不通过,提示'off 的时候只删除一次',但是我测试时,事件名及函数相同时,都可以删掉。

    class EventEmitter {
      constructor() {
        this.eventArr = [];
      }
      on(eventName,fun){
        this.eventArr.push({'eventName':eventName,'fun':fun});
      }
      emit(eventName,...args){
        this.eventArr.forEach((obj)=>{
          if(obj.eventName==eventName)
          {
            var argumentsArr = Array.prototype.slice.call(...args);
            obj.fun(...args);
          }
        })
      }
      off(eventName, func){
       var self = this;
       var arr=[]
        this.eventArr.forEach((obj,index)=>{
          if (obj.eventName != eventName || obj.fun!=func)
          {
            arr.push(obj);
          }
        })
        this.eventArr = arr;
      }
      /* TODO */
    }
    

  • 0

    class EventEmitter{
          constructor(){
            this.events = new Map()
            this.funcs = new Set()
          }
          on(eventName,func){
            this.events.set(eventName,this.funcs.add(func))
          }
          emit(eventName,...args){
            for(let [key,val] of this.events.entries()){
              if(eventName === key){
                for(let i of this.funcs.values()){
                  i(...args)
                }
              }
            }
          }
          off(eventName,func){
            for(let [key,val] of this.events.entries()){
              if(eventName === key && val.has(func)){
                this.funcs.delete(func)
              }else{
                this.evetns.delete(key)
              }
            }
          }
        }
    

    示例全部通过,提交提示事件没有被触发


  • 0

    class EventEmitter {
      /* TODO */
      constructor() {
        this.handlers = {}
      }
      on(eventName, handle) {
        if(!this.handlers.hasOwnProperty(eventName)){
          this.handlers[eventName] = []
        }
        this.handlers[eventName].push(handle)
      }
      off(eventName, handle) {
        if(!this.handlers.hasOwnProperty(eventName)) return 
        //获取下标,并删除
        let index = this.handlers[eventName].indexOf(handle)
        this.handlers[eventName].splice(index,1)
      }
      emit(eventName, ...params) {
        if(!this.handlers.hasOwnProperty(eventName)) return 
        //事件队列依次执行
        this.handlers[eventName].map(handle => {
          handle(...params)
        })
      }
    }
    
    

  • 0

    class EventEmitter {
    /* TODO */
    constructor() {
    this.listeners = [];
    }
    on(eventName,func){
    if(this.listeners.filter((listener)=>
    listener.eventName === eventName && listener.func == func
    ).length==0){
    this.listeners.push({
    eventName:eventName,
    func:func
    });
    }
    }
    emit(eventName,...arg){
    const dealListeners = this.listeners.filter((listener)=>{
    return listener.eventName === eventName
    });
    for (let i in dealListeners){
    dealListeners[i].func(...arg);
    }
    }
    off(eventName, func){
    for (let i in this.listeners){
    if(this.listeners[i].eventName === eventName && this.listeners[i].func == func){
    this.listeners.splice(i,1);
    break;
    }
    }
    }
    }
    我在浏览器跑可以 为什么提示事件没触发


  • 0

    终于搞对了,半小时
    class EventEmitter{

    		constructor(){
    			this.events= {};
    		}
    
    		on(eventName,fn){
    			let fnList = this.events[eventName]||[];
    			fnList.push(fn)
    			if(eventName){
    				this.events[eventName] = fnList;
    			}
    		}
    
    		emit(eventName,...agr){
    			let funcs = this.events[eventName];
    			if(funcs && funcs.length){
        			for(let j=0;j<funcs.length;j++){
        				funcs[j](...agr);
        			}
        		}
        	}
    		
    		off(eventName,fn){
    			let funcs = this.events[eventName];
    			if(fn){
    				  this.events[eventName].splice(fn,1);
    			}else{
    				delete this.events[eventName]
    			}
    		}
    	}

  • 0

    class EventEmitter {
      constructor () {
        this.store = {}
      }
    
      on (type, method) {
        if (this.store.hasOwnProperty(type)) {
          this.store[type].push(method)
        } else {
          this.store[type] = []
          this.store[type].push(method)
        }
      }
    
      emit (type, ...args) {
        for (let m of this.store[type]) {
          m(...args)
        }
      }
    
      off (type, method) {
        let index = this.store[type].indexOf(method)
        this.store[type].splice(index, 1)
      }
    }
    

    怎么感觉还有些东西没考虑到...


  • 0

    class EventEmitter {
      constructor() {
        this.onList = [];
      }
      on(name, fn) {
        this.onList.push({
          name,
          fn
        });
      }
      emit(name, ...param) {
        this.onList.map((o) => {
          if (o.name === name) {
            o.fn(...param);
          }
        })
      }
      off(name, fn) {
        let i = this.onList.findIndex((value) => {
          return value.name == name;
        })
        if (~i && fn == this.onList[i].fn) {
          this.onList.splice(i, 1);
        }
      }
    }
    

    自己测试貌似是可以,但是提交的时候总是提醒 :参数没有传入


  • 0

    class EventEmitter {
      constructor() {
        this.events = {};
      }
    
      on(eventName, callback) {
        if (!this.events[eventName]) {
          this.events[eventName] = []
        }
        this.events[eventName].push(callback);
        return this;
      }
    
      emit(eventName, ...args) {
        if (this.events[eventName].length) {
          this.events[eventName].forEach(fn => {
            if (typeof fn === 'function') {
              fn(...args);
            }
          });
        }
        return this;
      }
    
      off(eventName, callback) {
        if (this.events[eventName].length) {
          const pos = this.events[eventName].findIndex(fn => fn === callback);
          this.events[eventName].splice(pos, 1);
        } else {
          delete this.events[eventName];
        }
        return this;
      }
    }
    

    可以链式调用


  • 0

    很简洁的写法

    class EventEmitter {
      constructor() {
        this.events = new Map()
      }
      
      on(event, cb) {
        this.events.has(event) ? this.events.get(event).push(cb) : this.events.set(event, [cb])
      }
      
      emit(event, ...args){
        this.events.get(event).map(v => v(...args))
      }
      
      off(event, cb) {
        this.events.get(event).forEach((v, i) => {
          if(cb === v) this.events.get(event).splice(i,1)
        })
      }
    }
    

  • 0

    @Saku#36 实现一个 EventEmitter 中说:

    对设计模式一脸懵逼 参考代码后写了出来 理解后还是挺好懂的

    class EventEmitter {
      constructor() {
        this.handlers = {}
      }
      
      on(eventName, func) {
        let callbacks = eventName in this.handlers ? this.handlers[eventName] : []
        callbacks.push(func)
        this.handlers[eventName] = callbacks
      }
      
      emit(eventName, ...args) {
        if (!eventName in this.handlers) return
        const callbacks = this.handlers[eventName]
        callbacks.map(cb => {
          cb(...args)
        })
      }
      
      off(eventName, func) {
        if (!eventName in this.handlers) return
        let callbacks = this.handlers[eventName]
        let index = callbacks.indexOf(func)
        callbacks.splice(index, 1)
      }
    }
    

  • 0

    第一遍代码本地运行通过,但是测试显示未调用

    class EventEmitter {
      constructor() {
        this.listener = {}
      }
      on(name, fn) {
        this.listener[name] = this.listener[name] || []
        const taskqueue = this.listener[name]
        if (!taskqueue.includes(fn)) {
          taskqueue.push(fn)
        }
      }
      emit(name, ...params) {
        if (name in this.listener) {
          this.listener[name].forEach((v) => {
            v.apply(null, params)
          })
        }
      }
      off(name, fn) {
        if (name in this.listener) {
          const index = this.listener[name].indexOf(fn)
          this.listener[name].splice(index, 1)
        }
      }
    }
    

    第二次仅仅把判断条件去掉了,就测试通过了,这算Bug嘛??

    class EventEmitter {
      constructor() {
        this.listener = {}
      }
      on(name, fn) {
        this.listener[name] = this.listener[name] || []
        this.listener[name].push(fn)
      }
      emit(name, ...params) {
        this.listener[name].forEach((v) => {
          v.apply(null, params)
        })
      }
      off(name, fn) {
        const index = this.listener[name].indexOf(fn)
        this.listener[name].splice(index, 1)
      }
    }
    ···

  • 0

    class EventEmitter {
      message = {}
      on(eventName,func){
        if(typeof this.message[eventName] === 'undefined'){
          this.message[eventName] = [func]
        }else{
          this.message[eventName].push(func)
        }
      }
      emit(eventName,...args){
        if(!this.message[eventName]){
          return;
        }
        for(var i =0;i<this.message[eventName].length;i++){
          this.message[eventName][i].apply(this,args)
        }
      }
      off(eventName,func){
        if(this.message[eventName] instanceof Array){
          var index = this.message[eventName].indexOf(func)
          if(index<0){
            return
          }else{
            this.message[eventName].splice(index,1)
          }
        }
      }
    }
    

  • 0

    class EventEmitter {
      constructor() {
        this.messageBox = {};
      }
      on(eventName, func) {
        this.messageBox[eventName] = this.messageBox[eventName] || [];
        this.messageBox[eventName].push(func);
      }
      emit(eventName, ...args) {
        this.messageBox[eventName].forEach(fun => fun.apply(null, args));
      }
      off(eventName, func) {
        let arr = this.messageBox[eventName];
        for (var i = 0; i < arr.length; i++) {
          if (arr[i] === func) {
            break;
          }
        }
        this.messageBox[eventName].splice(i, 1);
      }
    }
    

    不算太难


  • 0

    说我事件没有触发0.0,可我试了跟题目的要求一模一样啊-.-,求解。。。
    ——————————————————————————————————————————
    已解决,把on方法中的

    if (event.indexOf(callback) === -1) {
        event.push(callback);
    }
    

    这个判断去掉就可以提交了,无伤大雅的问题~XD

    class EventEmitter {
        constructor() {
            this.state = {
                events: {}
            }
        }
        on(eventName, callback) {
            const event = this.state.events[eventName];
            if (event) {
                if (event.indexOf(callback) === -1) {
                    event.push(callback);
                }
            } else {
                this.state.events[eventName] = [callback];
            }
        }
        off(eventName, callback) {
            const event = this.state.events[eventName] || [];
            const callbackIndex = event.indexOf(callback);
            event.splice(callbackIndex, 1);
        }
        emit(eventName, ...params) {
            const event = this.state.events[eventName] || [];
            event.forEach(e => e(...params));
        }
    }
    

登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待