面试复习题-手写发布订阅

68 阅读2分钟

✊不积跬步,无以至千里;不积小流,无以成江海

思路

发布订阅本质是一种设计模式,是一个代码的模板。

具体实现思路:

  1. 首先定义一个变量eventHub,作为一个接口实现我们通讯的中介。
  2. 这个变量有三个固定的接口,on emit off
  3. 在函数外面通过方法来调用它们,比如:有些时候通过点击去召唤eventHub.on;某些时刻不需要这个函数让它关闭eventHub.off;在3s之后触发eventHub.emit函数等方式
  4. 关注一下三个变量的输入和输出。输入:事件名字(类型),以及它的函数/数据。输出:on因为没人关心他的返回值,所以return undefined;off和on非常类似,所以也是return undifined;emit好像也没人关心它的返回值,因此还是undefined
  5. 接下来看每个函数需要实现的功能
  6. on:如果监听了一个事件,就把它放到任务队列里面。因此要定义一个队列,但是由于这个队列的内容和结果是一一映射的,所以其实这个队列是一个哈希表,定义为map。之后实现on,拿到当前队列中的第name个数据并push到fn中即可。但是由于我们要实现防御式编程,即去判断会不会在哪里出错,那么我们需要在编程之前进行判断,如果这个队列为undefined,我们就要初始化这个队列。
  7. 由于on和off比较类似,因此再实现一下off。off不需要初始化(因为一定存在了才off),但需要判断是否为空,如果为空就直接返回。如果不为空,就用indexOf去找队列中是否含有含有fn这个函数。如果index小于0,则直接return;如果没有小于0,则利用splice方法,输入索引+参数,达到删掉哪里删掉几个的功能。
  8. 最后实现emit的功能。首先判断是不是为空,如果为空直接return。如果不为空就用map遍历一下,对队列中的每一个f函数进行调用,再传入data
  9. 因为on/off/emit的返回都是undefined,所以可以删掉所有的return undefined

实现


const eventHub = {
    map: {},
    on: (name, fn)=>{
    //入队
    //if (eventHub.map[name] === undefined){
    // eventHub.map[name] = []}
    // 将上面的内容转化为1行
    eventHub.map[name] = eventHub.map[name] || []
    eventHub.map[name].push(fn)
    //return undefined
    },

    emit: (name, data)=>{
    if (!eventHub.map[name]) {return}
    eventHub.map[name].map(f => f(data))
    //return undefined
    },

    off: (name, fn)=>{
    
    if (!eventHub.map[name]) {return}
    const index = eventHub.map[name].indexOf(fn)
    if(index < 0){return}
    eventHub.map[name].splice(index,1)
    //return undefined
    }
}

eventHub.on('click',f1)
eventHub.off('click',f1)
setTimeout(()=>{
    eventHub.emit('click', f2)
}, 3000)


///
eventHub.on('click', console.log)
eventHub.on('click',console.error)
setTimeout(()=>{
    eventHub.emit('click', 'hello')
}, 3000)
也可以先on再off一下