• js手写题汇总(面试前必刷)


    event模块

    实现node中回调函数的机制,node中回调函数其实是内部使用了观察者模式

    观察者模式:定义了对象间一种一对多的依赖关系,当目标对象Subject发生改变时,所有依赖它的对象Observer都会得到通知。

    function EventEmitter() {
       
      this.events = new Map();
    }
    
    // 需要实现的一些方法:
    // addListener、removeListener、once、removeAllListeners、emit
    
    // 模拟实现addlistener方法
    const wrapCallback = (fn, once = false) => ({
        callback: fn, once });
    EventEmitter.prototype.addListener = function(type, fn, once = false) {
       
      const hanlder = this.events.get(type);
      if (!hanlder) {
       
        // 没有type绑定事件
        this.events.set(type, wrapCallback(fn, once));
      } else if (hanlder && typeof hanlder.callback === 'function') {
       
        // 目前type事件只有一个回调
        this.events.set(type, [hanlder, wrapCallback(fn, once)]);
      } else {
       
        // 目前type事件数>=2
        hanlder.push(wrapCallback(fn, once));
      }
    }
    // 模拟实现removeListener
    EventEmitter.prototype.removeListener = function(type, listener) {
       
      const hanlder = this.events.get(type);
      if (!hanlder) return;
      if (!Array.isArray(this.events)) {
       
        if (hanlder.callback === listener.callback) this.events.delete(type);
        else return;
      }
      for (let i = 0; i < hanlder.length; i++) {
       
        const item = hanlder[i];
        if (item.callback === listener.callback) {
       
          hanlder.splice(i, 1);
          i--;
          if (hanlder.length === 1) {
       
            this.events.set(type, hanlder[0]);
          }
        }
      }
    }
    // 模拟实现once方法
    EventEmitter.prototype.once = function(type, listener) {
       
      this.addListener(type, listener, true);
    }
    // 模拟实现emit方法
    EventEmitter.prototype.emit = function(type, ...args) {
       
      const hanlder = this.events.get(type);
      if (!hanlder) return;
      if (Array.isArray(hanlder)) {
       
        hanlder.forEach(item => {
       
          item.callback.apply(this, args);
          if (item.once) {
       
            this.removeListener(type, item);
          }
        })
      } else {
       
        hanlder.callback.apply(this, args);
        if (hanlder.once) {
       
          this.events.delete(type);
        }
      }
      return true;
    }
    EventEmitter.prototype.removeAllListeners = function(type) {
       
      const hanlder = this.events.get(type);
      if (!hanlder) return;
      this.events.delete(type);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    实现Event(event bus)

    event bus既是node中各个模块的基石,又是前端组件通信的依赖手段之一,同时涉及了订阅-发布设计模式,是非常重要的基础。

    简单版:

    class EventEmeitter {
       
      constructor() {
       
        this._events = this._events || new Map(); // 储存事件/回调键值对
        this._maxListeners = this._maxListeners || 10; // 设立监听上限
      }
    }
    
    
    // 触发名为type的事件
    EventEmeitter.prototype.emit = function(type, ...args) {
       
      let handler;
      // 从储存事件键值对的this._events中获取对应事件回调函数
      handler = this._events.get(type);
      if (args.length > 0) {
       
        handler.apply(this, args);
      } else {
       
        handler.call(this);
      }
      return true;
    };
    
    // 监听名为type的事件
    EventEmeitter.prototype.addListener = function(type, fn) {
       
      // 将type事件以及对应的fn函数放入this._events中储存
      if (!this._events.get(type)) {
       
        this._events.set(type, fn);
      }
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    面试版:

    class EventEmeitter {
       
      constructor() {
       
        this._events = this._events || new Map(); // 储存事件/回调键值对
        this._maxListeners = this._maxListeners || 10; // 设立监听上限
      }
    }
    
    // 触发名为type的事件
    EventEmeitter.prototype.emit = function(type, ...args) {
       
      let handler;
      // 从储存事件键值对的this._events中获取对应事件回调函数
      handler = this._events.get(type);
      if (args.length > 0) {
       
        handler.apply(this, args);
      } else {
       
        handler.call(this);
      }
      return true;
    };
    
    // 监听名为type的事件
    EventEmeitter.prototype.addListener = function(type, fn) {
       
      // 将type事件以及对应的fn函数放入this._events中储存
      if (!this._events.get(type)) {
       
        this._events.set(type, fn);
      }
    };
    
    // 触发名为type的事件
    EventEmeitter.prototype.emit = function(type, ...args) {
       
      let handler;
      handler = this._events.get(type);
      if (Array.isArray(handler)) {
       
        // 如果是一个数组说明有多个监听者,需要依次此触发里面的函数
        for (let i = 0; i < handler.length; i++) {
       
          if (args.length > 0) {
       
            handler[i].apply(this, args);
          } else {
       
            handler[i].call(this
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    Vega Prime入门教程12.01:运行测试
    Stream手动分页
    linux高级篇基础理论四(rsync,inotify,squid,KVM虚拟机)
    Windows平台docker安装redis
    经验分享,免费商标查询网站
    微服务Day2——Nacos注册中心入门
    单点架构、集群架构、服务化架构、SOA、微服务到底有什么联系和关系?
    【Vue面试题十九】、Vue常用的修饰符有哪些有什么应用场景?
    java毕业设计乒乓球俱乐部管理源码+lw文档+mybatis+系统+mysql数据库+调试
    Dubbo3应用开发—协议(Dubbo协议、REST协议 、gRPC协议、Triple协议)
  • 原文地址:https://blog.csdn.net/helloworld1024fd/article/details/127765597