处理集合里的每一项是一个非常普通的操作,JavaScript提供了许多方法来迭代一个集合,从简单的for和for each循环到 map(),filter() 和 array comprehensions(数组推导式)。在JavaScript 1.7中,迭代器和生成器在JavaScript核心语法中带来了新的迭代机制,而且还提供了定制 for…in 和 for each 循环行为的机制。
迭代器
迭代器是一个每次访问集合序列中一个元素的对象,并跟踪该序列中迭代的当前位置。在JavaScript中迭代器是一个对象,这个对象提供了一个 next() 方法,next() 方法返回序列中的下一个元素。当序列中所有元素都遍历完成时,该方法抛出 StopIteration 异常。
迭代器对象一旦被建立,就可以通过显式的重复调用next(),或者使用JavaScript的 for…in 和 for each 循环隐式调用。
简单的对对象和数组进行迭代的迭代器可以使用 Iterator() 被创建:
一旦初始化完成,next() 方法可以被调用来依次访问对象的键值对:
for…in 循环可以被用来替换显式的调用 next() 方法。当 StopIteration 异常被抛出时,循环会自动终止。
如果你只想迭代对象的 key 值,可以往 Iterator() 函数中传入第二个参数,值为 true:
使用 Iterator() 访问对象的一个好处是,被添加到 Object.prototype 的自定义属性不会被包含在序列对象中。
Iterator() 同样可以被作用在数组上:
就像遍历对象一样,把 true 当做第二个参数传入遍历的结果将会是数组索引:
使用 let 关键字可以在循环内部分别分配索引和值给块变量,还可以解构赋值(Destructuring Assignment):
声明自定义迭代器
一些代表元素集合的对象应该用一种指定的方式来迭代。
1.迭代一个表示范围(Range)的对象应该一个接一个的返回这个范围包含的数字 2.一个树的叶子节点可以使用深度优先或者广度优先访问到 3.迭代一个代表数据库查询结果的对象应该一行一行的返回,即使整个结果集尚未全部加载到一个单一数组 4.作用在一个无限数学序列(像斐波那契序列)上的迭代器应该在不创建无限长度数据结构的前提下一个接一个的返回结果
JavaScript 允许你写自定义迭代逻辑的代码,并把它作用在一个对象上
我们创建一个简单的 Range 对象,包含低和高两个值:
现在我们创建一个自定义迭代器,它返回一个包含范围内所有整数的序列。迭代器接口需要我们提供一个 next() 方法用来返回序列中的下一个元素或者是抛出 StopIteration 异常。
我们的 RangeIterator 通过 range 实例来实例化,同时维持一个 current 属性来跟踪当前序列的位置。
最后,为了让 RangeIterator 可以和 Range 结合起来,我们需要为 Range 添加一个特殊的 __iterator__ 方法。当我们试图去迭代一个 Range 时,它将被调用,而且应该返回一个实现了迭代逻辑的 RangeIterator 实例。