关于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指向,原型链,原型加载,迭代器,底层调用关系等较为熟悉,那么这道题就是简单的封装过程
最后
感谢你能看到这里,笔者能力有限在文章存在的逻辑或表达问题请多包涵,如果对某个细节点存在疑问欢迎评论区讨论,如果文章对你有帮助请用点赞和收藏回应我 :)