zoukankan      html  css  js  c++  java
  • 前端面试(蚂蚁金服笔试)

    最近参加了一次蚂蚁金服的面试,其中有两道笔试题,分别是手写事件总线和手写模板引擎

    手写模板引擎比较复杂,除了需要识别 {{data.name}} 这种基本情况之外, 还要兼顾 {{data.info[1]}}{{data.others["about"]}}

    于是先记录下手写事件总线,后面再完善手写模板引擎的代码

     

    一、什么是事件总线

    在 Vue 2.x 中,有两种能在任意组件中传参的方式:状态管理 Vuex 和事件总线 EventBus

    但 EventBus 并非 Vue 首创,它作为一种事件的发布订阅模式,一直活跃在各种代码框架中

    EventBus 化了各个组件之间进行通信的复杂度,其工作原理在于对事件的监听与手动触发:

    // 实例化事件总线
    const events = new EventBus();
    
    // 监听自定义事件
    events.on('my-event', (value) => {
      console.log(value);
    });
    
    // 触发事件
    events.emit('my-event', 'helloworld');

    而这种先注册事件监听函数,然后通过触发事件来传参的行为其实是一种发布订阅模式 

     

    二、发布订阅模式

    发布订阅模式是一种广泛应用于异步编程的模式,是回调函数的事件化,常常用来解耦业务逻辑

    作为一个事件总线,它应当具备一个任务队列,以及三个方法:订阅方法、发布方法、取消订阅

    class EventBus {
      constructor() {
        this.tasks = {}; // 按事件名称创建任务队列
      }
      // 注册事件(订阅)
      on() {}
      // 触发事件(发布)
      emit() {}
      // 移除指定回调(取消订阅)
      off() {}
    }

     

    首先来实现订阅方法 on()

    它的作用是将事件的处理函数加入任务队列,所以需要接收两个参数:事件名称、事件的处理函数

    /**
     * 注册事件(订阅)
     * @param {String} type  事件名称
     * @param {Function} fn  回调函数
     */
    on(type, fn) {
      // 如果还没有注册过该事件,则创建对应事件的队列
      if (!this.tasks[type]) {
        this.tasks[type] = [];
      }
      // 将回调函数加入队列
      this.tasks[type].push(fn);
    }

     

    然后是触发事件的方法 emit()

    其功能是每触发一次事件,会执行对应事件的所有回调函数。所以它的参数必须有一个是事件名称,另外还可以传入一个参数作为回调函数的参数

    /**
     * 触发事件(发布)
     * @param {String} type  事件名称
     * @param {...any} args  传入的参数,不限个数
     */
    emit(type, ...args) {
      // 如果该事件没有被注册,则返回
      if (!this.tasks[type]) {
        return;
      }
      // 遍历执行对应的回调数组,并传入参数
      this.tasks[type].forEach(fn => fn(...args));
    }

     

    最后是注销方法 off(),它将需要注销的事件处理函数从对应事件的任务队列中清除

    /**
     * 移除指定回调(取消订阅)
     * @param {String} type  事件名称
     * @param {Function} fn  回调函数
     */
    off(type, fn) {
      const tasks = this.tasks[type];
    // 校验事件队列是否存在 if (!Array.isArray(tasks)) { return; } // 利用 filter 删除队列中的指定函数 this.tasks[type] = tasks.filter(cb => fn !== cb); }

     到这里一个简单的事件总线就已经完成,可以通过第一部分的测试代码进行测试

     

    三、完整代码

    通常事件总线内除了上面提到的三种方法外,还会包含一个 once() 方法,用来注册一个只能执行一次的事件,会在下面的代码中体现

    class EventBus {
      constructor() {
        this.tasks = {}; // 按事件名称创建任务队列
      }
    
      /**
       * 注册事件(订阅)
       * @param {String} type  事件名称
       * @param {Function} fn  回调函数
       */
      on(type, fn) {
        // 如果还没有注册过该事件,则创建对应事件的队列
        if (!this.tasks[type]) {
          this.tasks[type] = [];
        }
        // 将回调函数加入队列
        this.tasks[type].push(fn);
      }
      
      /**
       * 注册一个只能执行一次的事件
       * @params type[String] 事件类型
       * @params fn[Function] 回调函数
       */
      once(type, fn) {
        if (!this.tasks[type]) {
          this.tasks[type] = [];
        }
    
        const that = this;
        // 注意该函数必须是具名函数,因为需要删除,但该名称只在函数内部有效
        function _once(...args) {
          fn(...args);
          that.off(type, _once); // 执行一次后注销
        }
    
        this.tasks[type].push(_once);
      }
    
      /**
       * 触发事件(发布)
       * @param {String} type  事件名称
       * @param {...any} args  传入的参数,不限个数
       */
      emit(type, ...args) {
        // 如果该事件没有被注册,则返回
        if (!this.tasks[type]) {
          return;
        }
        // 遍历执行对应的回调数组,并传入参数
        this.tasks[type].forEach((fn) => fn(...args));
      }
    
      /**
       * 移除指定回调(取消订阅)
       * @param {String} type  事件名称
       * @param {Function} fn  回调函数
       */
      off(type, fn) {
        const tasks = this.tasks[type];
        // 校验事件队列是否存在
        if (!Array.isArray(tasks)) {
          return;
        }
    
        // 利用 filter 删除队列中的指定函数
        this.tasks[type] = tasks.filter((cb) => fn !== cb);
      }
    }
  • 相关阅读:
    Kprobes—insight into the Linux kernel—replace kernel function with module
    Go将统治下一个十年
    linux—网络仿真开源软件—network simulator—ns
    Serval Project——Android
    CentOS7—Firefox—截图工具—fireshot插件
    Wi-Fi Direct技术
    国产CPU迷局 龙芯该如何参与市场竞争
    《深入理解Android:Wi-Fi,NFC和GPS》—android源码下载
    wifi direct—深入理解Wi-Fi P2P
    c语言学习基础:[1]开发工具介绍
  • 原文地址:https://www.cnblogs.com/wisewrong/p/14768071.html
Copyright © 2011-2022 走看看