这是一道面试题:

// 类型: 校招
// 时长: 30 分钟
// 姓名:
// 日期:

// 实现下面的 EventEmitter 类, 用于简单的事件管理.

// 提示:
// 运行代码快捷键: Ctrl + S 

class EventEmitter {

    emit(type, ...args) {

    }

    oncets(that, type, listener) {

    }

    on(type, listener) {

    }

    off(type, listener) {

    }
  }

  // 在不修改下面代码的情况下, 能满足下面列举的使用

  console.log('输出结果:');

  const target = new EventEmitter();

  // once

  target.once('ready', id => console.log('ready', id));

  target.emit('ready', 1);
  target.emit('ready', 2);

  const messageListener = (...args) => console.log(args);

  // on

  target.on('message', messageListener);
  target.emit('message', 'hello');
  target.emit('message', 'world', '!');

  // off
  target.off('message', messageListener);

  target.emit('message', 'nothing');

  // 输出结果参考

  // 输出结果:
  // ready 1
  // hello
  // world !
  // (off 后无输出)

我在此之前完全没有写过事件驱动型的程序,对事件驱动我还停留在DOM的事件管理上,所有这题没有做出来,但是当时的思路有一些了。
事后在查阅网上资料后完成了以下代码,特此记录:

// [makeflow: event-emitter]
// 类型: 校招
// 时长: 30 分钟
// 姓名:
// 日期:

// 实现下面的 EventEmitter 类, 用于简单的事件管理.

// 提示:
// 运行代码快捷键: Ctrl + S 

class EventEmitter {
    constructor() {
        this.eventList = {};
    }

    emit(type, ...args) {
        let event = this.eventList[type];
        if(!event){
            return false;
        }else if(typeof event =="function"){
            event(...args);//如果只有一个值就直接执行
        }else if(Array.isArray(event)){//循环遍历执行
             for(let i = 0;i < event.length;i++){
                 event[i](...args);
             }
        }
    }

    once(type, listener) {
        this.on(type, this.oncets(this, type, listener));
    }

    oncets(that, type, listener) {
        //执行回调时首先删除自己,再执行
        function funconce() {
            that.off(type,funconce);
            listener(arguments);
        }
        return funconce;
    }

    on(type, listener) {
        //注册事件
        let event = this.eventList[type];
        if(!event){//直接添加到数组
            this.eventList[type] = listener;
        }else if(typeof event == "function"){//注册第二个事件时把属性改为数组
            this.eventList[type] = [event, listener];
        }else if(Array.isArray(type)){//第三次之后直接向数组中添加函数体
            this.eventList[type].push(listener);
        }
    }

    off(type, listener) {
        let event = this.eventList[type];
        if(typeof event =="function"){
            if(event == listener){//一个值,直接删除
                delete this.eventList[type];
            }
        }else if(Array.isArray(event)){
            //多个值,找到相同的删除掉
            for(let i = 0;i < event.length;i++){
                if(this.eventList[type][i] === listener){
                    this.eventList[type][i] = this.eventList[type][this.eventList[type].length - 1];
                    this.eventList[type].pop();
                    i--;
                    if(this.eventList[type].length === 0){
                        delete this.eventList[type];
                    }
                }
            }
        }
    }
  }

  // 在不修改下面代码的情况下, 能满足下面列举的使用

  console.log('输出结果:');

  const target = new EventEmitter();

  // once

  target.once('ready', id => console.log('ready', id));

  target.emit('ready', 1);
  target.emit('ready', 2);

  const messageListener = (...args) => console.log(args);

  // on

  target.on('message', messageListener);
  target.emit('message', 'hello');
  target.emit('message', 'world', '!');

  // off
  target.off('message', messageListener);

  target.emit('message', 'nothing');

  // 输出结果参考

  // 输出结果:
  // ready 1
  // hello
  // world !
  // (off 后无输出)

最后大致完成了,校招题都这样啊,难受。


如果本文有帮助到你,可以给站长打赏一杯下午茶