面试官:请手写一个EventBus,让我看看你的代码能力!

持续创作,加速成长!这是我参与「日新计划 6 月更文挑战」的第1天,点击查看活动详情

前言

EventBus是事件总线的意思,可不是什么数组的定义件车。 事件总线模式在工作中经常使用,在面试中也很容易问到。甚至在很多面试中会数组的定义让你手写一个EventBus,那么EventBus到底是个什么东西,今天我们就来数组学一学!

1数组去重方法.什么是EventBus

所谓事件总线模式,其实就和发布订阅模式非常类似,比如我们订阅了一个公众号,公众号发布文章之后我们就能收到变量泵信息,这就是一种订阅发布的关系。

再比如在Vue项目中,面试常见问题及回答技巧我们可以初始化英文使用$on$emit来实现事件的监听和触发,这其实就是一种事件总线的思想在里面数组去重,只不过Vue帮我们实现好了。

在我们的JavaScript面试技巧和话术大全中,可以给元素添加一个初始化sdk什么意思点击监听事件,当用户点击的时候,点击事件怎会被执行,这也是一种事件总线的思想在里面,就好比元素订阅了点击事件,用户发布或出触发点击事件。

从上可以看出,事件总线模式在我们的开发中数组的定义经常出现,我们也可以通过变量一张图来更加清楚的认识什面试问题大全及答案大全么是事件总线。

面试官:请手写一个EventBus,让我看看你的代码能力!

上图很清晰的描述了EventBus的角色是什么,它主要承担的是一个发布订阅的责任,比如有人发布了信息出来,那其他通信工程人如何接收这些信息呢?其他人面试自我介绍变量名以通过Eve初始化电脑时出现问题ntBus来订阅这些信息,当有信面试常见问题及回答技巧息发布的时候,事变量是什么意思件总线就将这些信息传播变量之间的关系给订阅者。

2.乞丐版EventBus

既然我们了解了EventBus的原理后,我们便可以手动实现一个来。我们步子不能面试迈的太大,先来一个乞丐版,实现嘴贱的发布订阅功能。

实现目标:

  • 使用$on订阅事件
  • 使用$emit发布事件

代码示例:

<script>
  class EventBus {
    // 定义所有事件列表,格式如下:
    // {
    //   key: Array,
    //   key: Array,
    // } 
    // Array存储的是注册的回调函数
    constructor() {
      this.eventObj = {}; // 用于存储所有订阅事件
    }
    // 订阅事件,类似监听事件$on('key',()=>{})
    $on(name, callbcak) {
      // 判断是否存储过
      if(!this.eventObj[name]) {
        this.eventObj[name] = [];
      }
      this.eventObj[name].push(callbcak); // 往事件数组里面push
    }
    // 发布事件,类似于触发事件$emit('key')
    $emit(name) {
      // 获取存储的事件回调函数数组
      const eventList = this.eventObj[name];
      // 执行所有回调函数
      for (const callbcak of eventList) {
        callbcak();
      }
    }
  }
  // 初始化EventBus
  let EB = new EventBus();
  // 订阅事件
  EB.$on('key1', () => {
    console.info("我是订阅事件A");
  })
  EB.$on("key1", () => {
    console.info("我是订阅事件B");
  })
  EB.$on("key2", () => {
    console.info("我是订阅事件C");
  })
  // 发布事件
  EB.$emit('key1');
  EB.$emit('key2');
</script>

数组指针出结果:

面试官:请手写一个EventBus,让我看看你的代码能力!

上段代码中我们声明了一个EventBus类,专门用变量名来处理我们的发布订阅操作。上段代码的整体思路如下:

  1. 首先订阅了一堆事件key1key2等等,当这些事件被触发时执行回调函数。
  2. 订阅的这些事件key1...都需要存储到EventBus中去,定面试技巧变量eventOb面试自我介绍3分钟通用j存储。
  3. 当其它用户或模块触发订阅的事件key1...等,Ev变量类型有哪些entBus变量英语eventObj中查找,找到则则触通信工程专业发存储的回调函数通信工程专业

上面就是一个最简单的EventBus了,只初步实现了$on$emit

3.传参版EventBus

虽然说乞丐版的EventBus也能用,但通信人家园是它的场景很有限。我们使用EventBus是很多时候都是需要初始化失败是怎么解决传参的,就好比我订阅了一个公众号,结果公众号每初始化电脑次发布的内容都是空的,很明显不行。所以我们需要在发变量名的命名规则布事件$emit的时候传参,然后在订阅事件的回调函数里面可以接收参数。

实现目标:

  • 使用$on订阅事件
  • 使用$emit发布事数组词
  • $emit发布事件可以传参

示例代码:

<script>
  class EventBus {
    // 定义所有事件列表,格式如下:
    // {
    //   key: Array,
    //   key: Array,
    // } 
    // Array存储的是注册的回调函数
    constructor() {
      this.eventObj = {}; // 用于存储所有订阅事件
    }
    // 订阅事件,类似监听事件$on('key',()=>{})
    $on(name, callbcak) {
      // 判断是否存储过
      if (!this.eventObj[name]) {
        this.eventObj[name] = [];
      }
      this.eventObj[name].push(callbcak); // 往事件数组里面push
    }
    // 发布事件,类似于触发事件$emit('key')
    $emit(name, ...args) {
      // 获取存储的事件回调函数数组
      const eventList = this.eventObj[name];
      // 执行所有回调函数且传入参数
      for (const callbcak of eventList) {
        callbcak(...args);
      }
    }
  }
  // 初始化EventBus
  let EB = new EventBus();
  // 订阅事件
  EB.$on('key1', (name, age) => {
    console.info("我是订阅事件A:", name, age);
  })
  EB.$on("key1", (name, age) => {
    console.info("我是订阅事件B:", name, age);
  })
  EB.$on("key2", (name) => {
    console.info("我是订阅事件C:", name);
  })
  // 发布事件
  EB.$emit('key1', "小猪课堂", 26);
  EB.$emit('key2', "小猪课堂");
</script>

输出结果:

面试官:请手写一个EventBus,让我看看你的代码能力!

上段代码我们实现了$emit传参,$on的回调可以接收参数的功能。这样我们的Eve通信大数据行程卡ntBus又变得完善了一点。比如有两个标签页需要通信,就可以使用我数组去重们这里的EventBus来进行实现。除此之外,Vue组件间的通讯也可以使用EventBus来进行实现,因为可以传递参数变量与函数

4.取消订阅版EventBus

既然有订阅,变量的定义那么就有取消订阅,我们可以订阅公众号,也可以取关公众号,这是理所当然的事。我们的EventB面试技巧和话术大全us也需要实现这样的功能,比如我们监听了某个事件,在一定情况下我们需要取消监听事件。

实现目标:

  • 使用$on订阅事件
  • 使用$e通信工程mit发布事件
  • $emit发布事件可以传参
  • 实现$off取消订阅

示例代码:

<script>
  class EventBus {
    // 定义所有事件列表,此时需要修改格式:
    // // {
    //   key: {
    //     id: Function,
    //     id: Function
    //   },
    //   key: Object,
    // } 
    // Array存储的是注册的回调函数
    constructor() {
      this.eventObj = {}; // 用于存储所有订阅事件
      this.callbcakId = 0; // 每个函数的ID
    }
    // 订阅事件,类似监听事件$on('key',()=>{})
    $on(name, callbcak) {
      // 判断是否存储过
      if (!this.eventObj[name]) {
        this.eventObj[name] = {};
      }
      // 定义当前回调函数id
      const id = this.callbcakId++;
      this.eventObj[name][id] = callbcak; // 以键值对的形式存储回调函数
      return id; // 将id返回出去,可以利用该id取消订阅
    }
    // 发布事件,类似于触发事件$emit('key')
    $emit(name, ...args) {
      // 获取存储的事件回调函数数组
      const eventList = this.eventObj[name];
      // 执行所有回调函数且传入参数
      for (const id in eventList) {
        eventList[id](...args);
      }
    }
    // 取消订阅函数,类似于$off('key1', id)
    $off(name, id) {
      // 删除存储在事件列表中的该事件
      delete this.eventObj[name][id];
      console.info(`id为${id}的事件已被取消订阅`)
      // 如果这是最后一个订阅者,则删除整个对象
      if (!Object.keys(this.eventObj[name]).length) {
        delete this.eventObj[name];
      }
    }
  }
  // 初始化EventBus
  let EB = new EventBus();
  // 订阅事件
  EB.$on('key1', (name, age) => {
    console.info("我是订阅事件A:", name, age);
  })
  let id = EB.$on("key1", (name, age) => {
    console.info("我是订阅事件B:", name, age);
  })
  EB.$on("key2", (name) => {
    console.info("我是订阅事件C:", name);
  })
  // 发布事件key1
  EB.$emit('key1', "小猪课堂", 26);
  // 取消订阅事件
  EB.$off('key1', id);
  // 发布事件key1
  EB.$emit('key1', "小猪课堂", 26);
  // 发布事件
  EB.$emit('key2', "小猪课堂");
</script>

输出结果:

面试官:请手写一个EventBus,让我看看你的代码能力!

既然我们需要取消订阅某一个事件,那么我们就需要给该事件添加一个标识,这样才可以在茫茫人海中找到它,并且取阅它。所以我们这个修改了eventObj事件对象的存储结构,其中的每个key存储的不在是数组了,而是对象类型。

实现的变量英语整体思路如下:

  1. 给每个订阅事件添加唯一标识id
  2. 之前事件key存储的是事件回调函数数组,现在改成事件回调函数对象,键为id,值为回调函数。
  3. 订阅事件的面试问题大全及答案大全时候返回一个id
  4. 取消订阅的时候通过id找到存储在eventObj中的事件函数,并且删掉它。

5.执行一次版EventBus(完整版)

虽然前面实现的EventBus基本能够满足我们的项目需求了,但是还有一种情景我们需要考虑,比如我面试常见问题及回答技巧订阅了某个公众号,但是我只允许你给我发送一次消息,然后我们取关你。虽然在公众号的场景下这种需求比较变态,但是在我们的项目场景下这可能变量泵就是比较正常初始化英文的了,我只想让某一个订阅事件只执行一次,这非常正常。

  • 使用$on订阅事件
  • 使用$变量值emit发布事件
  • $emit发布事件可以传参
  • 实现$off取消订阅
  • 实现$once执行一次

示例代码:

<script>
  class EventBus {
    // 定义所有事件列表,此时需要修改格式:
    // // {
    //   key: {
    //     D+id: Function,
    //     id: Function
    //   },
    //   key: Object,
    // } 
    // Array存储的是注册的回调函数
    constructor() {
      this.eventObj = {}; // 用于存储所有订阅事件
      this.callbcakId = 0; // 每个函数的ID
    }
    // 订阅事件,类似监听事件$on('key',()=>{})
    $on(name, callbcak) {
      // 判断是否存储过
      if (!this.eventObj[name]) {
        this.eventObj[name] = {};
      }
      // 定义当前回调函数id
      const id = this.callbcakId++;
      this.eventObj[name][id] = callbcak; // 以键值对的形式存储回调函数
      return id; // 将id返回出去,可以利用该id取消订阅
    }
    // 发布事件,类似于触发事件$emit('key')
    $emit(name, ...args) {
      // 获取存储的事件回调函数数组
      const eventList = this.eventObj[name];
      // 执行所有回调函数且传入参数
      for (const id in eventList) {
        eventList[id](...args);
        // 如果是订阅一次,则删除
        if(id.indexOf('D') !== -1) {
          delete eventList[id];
        }
      }
    }
    // 取消订阅函数,类似于$off('key1', id)
    $off(name, id) {
      console.log(this.eventObj)
      // 删除存储在事件列表中的该事件
      delete this.eventObj[name][id];
      console.info(`${id}id事件已被取消订阅`)
      // 如果这是最后一个订阅者,则删除整个对象
      if (!Object.keys(this.eventObj[name]).length) {
        delete this.eventObj[name];
      }
    }
    // 订阅事件,只会执行一次,为了方便,id上直接加上一个标识d
    $once(name, callbcak){
      // 判断是否存储过
      if (!this.eventObj[name]) {
        this.eventObj[name] = {};
      }
      // 定义当前回调函数id,添加D则代表只执行一次
      const id = "D" + this.callbcakId++;
      this.eventObj[name][id] = callbcak; // 以键值对的形式存储回调函数
      return id; // 将id返回出去,可以利用该id取消订阅
    }
  }
  // 初始化EventBus
  let EB = new EventBus();
  // 订阅事件
  EB.$on('key1', (name, age) => {
    console.info("我是订阅事件A:", name, age);
  })
  EB.$once("key1", (name, age) => {
    console.info("我是订阅事件B:", name, age);
  })
  EB.$on("key2", (name) => {
    console.info("我是订阅事件C:", name);
  })
  // 发布事件key1
  EB.$emit('key1', "小猪课堂", 26);
  console.info("在触发一次key1")
  EB.$emit('key1', "小猪课堂", 26);
  // 发布事件
  EB.$emit('key2', "小猪课堂");
</script>

输出结果:

面试官:请手写一个EventBus,让我看看你的代码能力!

上段代码中我们第一次触发事件key1时,订阅事件AB都执行了,但是第二次触发事件key1时,只有订阅事件A执行了,说明订阅事件B已经取消订阅了。

整体实现思路:

  1. 使用$once订阅事件时,我们需要给该事件数组公式做个标识,以便识别出它只会执行一次。
  2. 为了方便,我们直接在id字段前面拼接D数组去重方法代表只会执行一次。
  3. 触发事件时,判断id上是否有D,如果有D通信技术,则执行完后删除该事件变量的定义

总结

本篇文章面试技巧和话术大全实现了一个较为简单的EventBus,但是也基本满足我们在项目中的使用了。想要实现EventBus,我们首要理解的就是发布订阅模式,然后我们在思考下面几个问题,基本上就能实现一个属于自己的EventBus了。

  • 订阅事件如何存储?
  • 如何传递参数?
  • 如何给每个订阅事件添加唯一标识?数组指针
  • 如何正确删除存储的订阅事件?
  • $on$emit主要担任的面试问题大全及答案大全是什么角色?初始化英文
  • 什么时发布订阅模式?

想明白面试问题了上面的问题那么EventBus我相信你也明白了,能够自己实现了。

如果觉得文章太繁琐或者没看懂,可以观看视频:小猪课堂

发表评论

提供最优质的资源集合

立即查看 了解详情