概念
在ES6之前,表示集合的数据结构有数组(Array)和对象(Object),而在ES6中又添加了Set和Map,所以现在有了四种数据结构,用户可以组合使用他们,定义自己的数据结构,那么就需要又统一的接口来处理不同的数据结构。
从遍历操作上看,Iterator就是解决不同的数据结构遍历的问题,任何数据结构只要部署了Iterator接口,就可以完成遍历操作(依次处理该数据结构的所有成员)(有点策略模式的意思)。
Iterator作用:
1:为各种数据结构,提供一个统一的,简便的访问接口。
2:使得数据结构的成员能够按某种次序排序。
3:ES6创造了一种新的遍历命令for...of循环(也就是说只要遍历了Iterator接口,就可以使用for...of进行遍历)
Iterator遍历过程:
1:创建一个指针对象,指向当前数据结构的起始位置。
2:第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
3:不断调用指针对象next方法,直到指针对象指向数据结构的结束位置
每次调用next()方法,都会返回数据结构当前成员的信息,
具体来说,就是返回一个包含value和done两个属性的对象,
value是当前成员的值,done是布尔值,表示当前遍历是否结束。
举个简单的例子(写一个生成遍历器的函数):
function makeIterator(array){
var nextIndex = 0;
return {
next:function(){
return nextInex < array.length?
{value:array[nextIndex++]}:
{done:true}
}
}
}
这里通过闭包的写法将nextIndex常驻在内存中,
并返回一个指针对象,这个对象内有个next函数,
函数返回了当前遍历指针指向的数据结构的某个元素
默认的Iterator接口
说完这些,接下来看看这个接口是怎么用的吧。
实际上,我们在遍历某种数据结构的时候,可能会直接用for循环遍历,
比如对象,我们先用Object.keys()方法来获取一个对象的所有属性名,
再用for(let i=0;i<arr.length;i++){}进行遍历,数组也一样,
而当一种数据结构部署了Iterator接口,则可以使用for...of循环遍历
for...of会自动去寻找Iterator接口,来实现循环机制
比如数组for(const item of arr){}
再比如Map:for(const [value,key] of map){}
这样就比之前的写法要简洁,简单得多。(当然还有更简单的扩展运算符...),
说完了实际的用法,我们再看看使用for...of,扩展运算符,会怎么操作吧,
ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性,
所以一个数据结构只要部署了Symbol.iterator属性,那么他就是可遍历的,
Symbol.iterator属性本身就是一个函数,是当前数据结构默认的遍历器生成函数,
属性名Symbol.iterator,是一个表达式,返回Symbol对象的iterator属性,是一个预定好的Symbol特殊值
下课面看看一个对象中部署专有的遍历器
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
这里的obj对象是可遍历的,遍历函数为上面规定好的Symbol.iterator对应的函数,
下面数据结构是原生就具有Symbol.iterator函数的
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
在具有Symbol.iterator属性的数据结构,调用这个属性,就可以得到遍历器对象
注意:如果Symbol.iterator对应的不是遍历器生成函数的话,就会报错
Iterator的实际应用
我们知道Iterator是为了遍历某种数据结构,那么,我们需要通过什么方式去遍历这种数据结构呢?
常用常见的就是for...of循环和扩展运算符了,还有yield,
yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
除此之外,还有其他场合会用到遍历器接口
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
Promise.all()
Promise.race()
遍历器对象的return()和throw()
遍历器中除了必写的next()函数,还可以写return()函数,
该方法会在break,或者throw抛出错误的时候调用
Iterator接口,就说这些比较常见的东西吧。