FE-Interview icon indicating copy to clipboard operation
FE-Interview copied to clipboard

请实现`$on,$emit`

Open lgwebdream opened this issue 5 years ago • 7 comments

lgwebdream avatar Jul 06 '20 16:07 lgwebdream

扫描下方二维码,获取答案以及详细解析,同时可解锁800+道前端面试题。

lgwebdream avatar Jul 06 '20 16:07 lgwebdream

function Events() {
  this.eventHub = {}
}

Events.prototype.$on = function(eventName, fn) {
  this.eventHub[eventName] = (this.eventHub[eventName] || []).concat(fn)
}

Events.prototype.$emit = function(eventName, args) {
  if (this.eventHub[eventName]) {
    this.eventHub[eventName].forEach((fn) => {
      fn(args)
    })
  }
}

Events.prototype.$off = function(eventName, fn) {
  if (this.eventHub[eventName]) {
    if (!fn) {
      this.eventHub[eventName] = []
    } else {
      this.eventHub[eventName] = this.eventHub[eventName].filter(fun => fun !== fn)
    }
  }
}

Events.prototype.$once = function(eventName, fn) {
  const fun = (...args) => {
    fn.apply(this, args)
    this.$off(eventName, fn)
  }
  this.$on(eventName, fun)
}
function test(a) {
  console.log(a)
}
var event = new Events()
event.$once('test', test)
event.$emit('test', 1)

523451928 avatar Jul 17 '20 01:07 523451928

class Event {
    constructor(){
        this.eventHub = {};
    }
    on(eventName, fn){
        (this.eventHub[eventName] || (this.eventHub[eventName] = [])).push(fn);
    }
    off(eventName, fn){
        if(fn) {
            if(Array.isArray(this.eventHub[eventName])) this.eventHub[eventName] = this.eventHub[eventName].filter(func => func !== fn);
        }else {
            this.eventHub[eventName] = [];
        }
    }
    emit(eventName, ...args) {
        if(Array.isArray(this.eventHub[eventName])) {
            this.eventHub[eventName].forEach(fn => {
                typeof fn === 'function' && fn.apply(this, args);
            });
        }
    }
    once(eventName, fn) {
        const onceWrap = (...args) => {
            fn.apply(this, args);
            this.off(event, fn);
        }
        this.on(eventName, onceWrap);
    }
}

function test(a) {
    console.log(a)
}
var event = new Event()
event.once('test', test)
event.emit('test', 1) // 1

GolderBrother avatar Aug 31 '20 15:08 GolderBrother

class Event {
    constructor(){
        this.eventHub = {};
    }
    on(eventName, fn){
        (this.eventHub[eventName] || (this.eventHub[eventName] = [])).push(fn);
    }
    off(eventName, fn){
        if(fn) {
            if(Array.isArray(this.eventHub[eventName])){
                console.log(this.eventHub[eventName].filter(func => func !== fn))
                this.eventHub[eventName] = this.eventHub[eventName].filter(func => {
                    return func !== fn
                });
            }
        }else {
            this.eventHub[eventName] = [];
        }
    }
    emit(eventName, ...args) {
        if(Array.isArray(this.eventHub[eventName])) {
            this.eventHub[eventName].forEach(fn => {
                typeof fn === 'function' && fn.apply(this, args);
            });
        }
    }
    once(eventName, fn) {
        const onceWrap = (...args) => {
            fn.apply(this, args);
            this.off(eventName, onceWrap);
        }
        this.on(eventName, onceWrap);
    }
}

nihaojob avatar Aug 18 '22 03:08 nihaojob

function Events() {
  this.eventHub = {}
}

Events.prototype.$on = function(eventName, fn) {
  this.eventHub[eventName] = (this.eventHub[eventName] || []).concat(fn)
}

Events.prototype.$emit = function(eventName, args) {
  if (this.eventHub[eventName]) {
    this.eventHub[eventName].forEach((fn) => {
      fn(args)
    })
  }
}

Events.prototype.$off = function(eventName, fn) {
  if (this.eventHub[eventName]) {
    if (!fn) {
      this.eventHub[eventName] = []
    } else {
      this.eventHub[eventName] = this.eventHub[eventName].filter(fun => fun !== fn)
    }
  }
}

Events.prototype.$once = function(eventName, fn) {
  const fun = (...args) => {
    fn.apply(this, args)
    this.$off(eventName, fn)
  }
  this.$on(eventName, fun)
}
function test(a) {
  console.log(a)
}
var event = new Events()
event.$once('test', test)
event.$emit('test', 1)

once方法会有问题,应该在 this.off中传入 eventName 和 onceWrap

nihaojob avatar Aug 18 '22 03:08 nihaojob


class EventEmitter {
  callbacks = new Map();

  on = (eventName, callback) => {
    if (!this.callbacks.has(eventName)) {
      return void this.callbacks.set(eventName, [callback]);
    }

    const currentEventCallbacks = this.callbacks.get(eventName);
    currentEventCallbacks.forEach(cb => {
      if (cb === callback) {
        return new Error("Try dupucate resgite callback");
      }
    });

    currentEventCallbacks.push(callback);
    this.callbacks.set(eventName, currentEventCallbacks);
  };

  emit = (eventName, ...args) => {
    if (!this.callbacks.has(eventName)) {
      return;
    }

    const currentEventCallbacks = this.callbacks.get(eventName);
    currentEventCallbacks.forEach(cb => {
      cb(...args);
    });
  };

  once = (eventName, callback) => {
    const executer = (...args) => {
      unsubscribe(eventName, executer);
      callback(...args);
    };
    this.on(eventName, executer);
  };

  unsubscribe = (eventName, callback) => {
    if (!this.callbacks.has(eventName)) {
      return;
    }

    const currentEventCallbacks = this.callbacks.get(eventName);
    const leftCallbacks = currentEventCallbacks.filter(cb => cb !== callback);
    if (leftCallbacks.length === 0) {
      return this.callbacks.delete(eventName);
    }
    this.callbacks.set(eventName, leftCallbacks);
  };
}

gaohan1994 avatar Apr 30 '24 06:04 gaohan1994