ES6---Iterator(for...of)

194 阅读4分钟

概念

在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接口,就说这些比较常见的东西吧。

资料参考:es6.ruanyifeng.com/#docs/itera…