关于js迭代器的一个面试题

243 阅读3分钟

关于js迭代器的一个面试题

面试题

  • 在不改变原式上下文的情况下,使表达式成立,且拿到正确的值

    const [v,w] = {a:1,b:2}
    

迭代器的思考

底层在进行解构赋值时,是调用了iterator将其转换为了一个迭代器,通过顺位next()方法调用的方式,来进行对应变量指针引用的指向

  • const [a,b] = [2,3]  // 底层实际调用了蝶iterable方法,将其变为了一个迭代器链表,调用next()取值后放入到了对应的变量位置上,每次解构都是next方法的调用导致了指针后移动
    
  • 迭代器是什么

    迭代器可以看做是一个链表,当你进行一次函数上下文调用后,他会根据执行yield语句的执行顺序组成一个链表并返回一个迭代器链表,此时你每次调用next()都会获取当前的值并完成指针下移

    // 当传入true时,返回 1->3->5的链表 ,为false时,返回 2->4->6的链表
    function* values(flag){
        if(flag){
        	yield 1
        	yield 3
        	yield 5
        } else{
            yield 2
        	yield 4
        	yield 6
        }
    }
    

引子

  • 由于Object原型对象上没有iterable方法,无法完成迭代器转换,但数组上有此方法,因此需要完成引用借用,将其挂载到Object原型对象上即可

    Object.prototype[Symbol.iterable] = Array.prototype[Symbol.iterable]  // 由于迭代器在Symbol.iterable身上,因此对象在引用的时候需要使用[]进行包裹,直接使用.的方式获取底层会直接调用toString方法当做对象处理,只有使用[]才会当做表达式解析
    const [v,w] = {a:1,b:2}  // 由于方法迭代器方法已经挂载完成,因此表达式成立,但无法完成对应数据的解构
    

方案尝试

由于上面我已经完成了迭代器的代理借用,此时对象也拥有了迭代的功能,此时有两个思考方向,一重写过程返回正确的数组,二为重写过程返回正确的迭代器

  • 方案一(返回数组)

  • 失败,会出现程序报错,这里就不展示细节了

  • 方案二(返回迭代器)

    成功,可以拿到正确的值,下面附上程序上下文

    Object.prototype[Symbol.iterator] = function* values(){
          const obj = this 
          const array = Object.values(obj)
          for (let index = 0; index < array.length; index++) {
            yield array[index];
          }
        }
    const [uv1,uv2] = {v1:'2',v2:'4'}
    expect(uv1).toBe('2')
    expect(uv2).toBe('4')
    

总结

  • 主要是对迭代器的运用,解构赋值实际上就是调用了底层的iterable方法将进行迭代器结构
  • 由于Object身上没有这个迭代器标识,因此需要添加借用代理完成操作
  • 如果你对this指向,原型链,原型加载,迭代器,底层调用关系等较为熟悉,那么这道题就是简单的封装过程

最后

感谢你能看到这里,笔者能力有限在文章存在的逻辑或表达问题请多包涵,如果对某个细节点存在疑问欢迎评论区讨论,如果文章对你有帮助请用点赞和收藏回应我 :)

精彩文章

Vue3实现简易typora - 掘金 (juejin.cn)

Vue3实现简易typora - 掘金 (juejin.cn)