前言
本文主要介绍 ES6 的 Iterator, Iterator 可以说在ES6中非常重要!是面试官经常会被问到的问题!坚持看到最后哟,后面才是重头戏!
一、for...of
在进入正题之前,我们先来了解下for...of循环的一些特性,它是ES6的标准,作为遍历所有数据结构的统一的方法。
1.遍历数组返回的是元素
const arr=[1,2,3,4]
for(let item of arr){
console.log(item); //1 2 3 4
}
可以看到打印输出数组每一个元素。
2.不能遍历不具有 iterator 属性的数据结构
let obj={
a:1,
b:2,
c:3
}
for(let item of obj){
console.log(item); //TypeError: obj is not iterable
}
可以看到遍历输出对象的元素时会报错: obj is not iterable,也就是obj不是可迭代的
3.不能遍历到数组原型上的属性
Array.prototype.c='d'//往数组原型上挂一个属性c
const arr=[1,2,3,4]
for(let item of arr){
console.log(item); //1 2 3 4
}
可以看到打印输出的依旧是1 2 3 4,没有输出数组原型上的属性。
由以上我们可以知道for...of遍历具有iterator 属性的数据结构,而数组就有iterator 属性,所以可以用 for...of遍历,而对象身上没有iterator 属性所以不可以用for...of遍历(一些特例除外)。
你们可能会想iterator到底是什么东西,for...of和我们接下来要讲的iterator迭代器有什么关联吗? 请看下文!
二、iterator(迭代器)
Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of
循环。Iterator 接口主要供for...of
消费。
ES6 规定,默认的 Iterator 接口部署在数据结构的
Symbol.iterator
属性,或者说,一个数据结构只要具有Symbol.iterator
属性,就可以认为是“可遍历的”(iterable)。
可能会有点晕?来个例子!
我们在浏览器的控制台里输入一个数组并输出,可以看到数组里的[[Prototype]]
内包含许多属性,其中就有Symbol.iterator
属性。
同时我们可以注意到:
Symbol.iterator
属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。
看下例:
let arr=[]
// arr={
// [Symbol.iterator]:function(){
// return //迭代器对象
// }
// } arr数组上有这样一个属性Symbol.iterator 外层加了[]代表此属性只可访问不可更改
可以看到数组身上的Symbol.iterator
属性返回的一个函数,既然是个函数就能调用:
返回的是一个迭代器对象Array Iterator{}!我们打开Array Iterator{}内层:
发现里面隐式继承了next属性!我们来使用一下!
我们可以发现返回的迭代器对象内的
next
属性可以取到数组内的值,next属性里的value
代表取到的值,done
代表是否还可以next,false代表能继续next,true代表不能next,已经到底了。
字节面试题
OK,清楚了解这些后,重头戏来了!来自字节面试题的一个问题!
题目:如下所示,想让你实现输出a,b。了解解构赋值的会知道数组和对象之间直接解构是不可行的。那怎么解决呢?
let [a,b]={a:1,b:2}
console.log(a,b);//TypeError: {(intermediate value)(intermediate value)} is not iterable
解决方案:
思路: 我们知道第一行等号左边的数组[a,b]
是可迭代的,右边的对象{a:1,b:2}
不可迭代的。那么我们应该‘使’命的想办法让右边的对象变成是可迭代的。既然对象身上没有迭代器属性,那我们就给它加一个!
实现: 我们给对象原型上加一个Symbol.iterator
属性,以此让对象具有可迭代属性。
Object.prototype[Symbol.iterator] = function(){//Symbol.iterator属性返回的是函数
return [] //此处应该返回的是一个迭代器对象,不是[],直接{}也不可行
}
let [a,b]={a:1,b:2}
console.log(a,b); //TypeError: undefined is not a function
我们可以看到报的错不再是not iterable,而是undefined is not a function!这是因为Symbol.iterator
return出来的一个迭代器对象,所以这样也是不可行的。
再来,我们想数组的解构只能往数组解构,那么我们把对象转成数组,就是硬生生的把对象的值转为[1,2],也就是把值抠出来不要key,那么此时才能解构成立。所以我们现在想让对象的迭代器属性把对象变成[1,2]。利用对象Object身上的values()
方法!答案揭晓!
Object.prototype[Symbol.iterator] = function(){//Symbol.iterator属性返回的是函数
//返回一个Array类型的可迭代对象
return Object.values(this)[Symbol.iterator]() //this指向实例对象,Object.values(this)得到的是数组
}
let [a,b]={a:1,b:2} //实例对象 相当于获得[1,2]
console.log(a,b); //1 2
tips:
Object.values()
---该方法返回一个给定对象自身的所有可枚举属性值的数组 。
总结
for...of
通常用来遍历Symbol.iterator
属性的数据结构,比如数组Iterator
接口主要供for...of
消费默认的 Iterator 接口部署在数据结构的
Symbol.iterator
属性。一个数据结构只要具有Symbol.iterator
属性,就可以认为是“可遍历的”。
本篇文章就到此为止啦,由于本人经验水平有限,难免会有纰漏,对此欢迎指正。如觉得本文对你有帮助的话,欢迎点赞收藏❤❤❤,您的点赞是持续写作的动力,感谢支持。