JavaScript高级程序设计(第4版)
上QQ阅读APP看书,第一时间看更新

7.1 理解迭代

在JavaScript中,计数循环就是一种最简单的迭代:

    for (let i = 1; i <= 10; ++i) {
      console.log(i);
    }

循环是迭代机制的基础,这是因为它可以指定迭代的次数,以及每次迭代要执行什么操作。每次循环都会在下一次迭代开始之前完成,而每次迭代的顺序都是事先定义好的。

迭代会在一个有序集合上进行。(“有序”可以理解为集合中所有项都可以按照既定的顺序被遍历到,特别是开始和结束项有明确的定义。)数组是JavaScript中有序集合的最典型例子。

    let collection = ['foo', 'bar', 'baz'];
    for (let index = 0; index < collection.length; ++index) {
      console.log(collection[index]);
    }

因为数组有已知的长度,且数组每一项都可以通过索引获取,所以整个数组可以通过递增索引来遍历。由于如下原因,通过这种循环来执行例程并不理想。

迭代之前需要事先知道如何使用数据结构。数组中的每一项都只能先通过引用取得数组对象,然后再通过[]操作符取得特定索引位置上的项。这种情况并不适用于所有数据结构。

遍历顺序并不是数据结构固有的。通过递增索引来访问数据是特定于数组类型的方式,并不适用于其他具有隐式顺序的数据结构。

ES5新增了Array.prototype.forEach()方法,向通用迭代需求迈进了一步(但仍然不够理想):

    let collection = ['foo', 'bar', 'baz'];
    collection.forEach((item) => console.log(item));
    // foo
    // bar
    // baz

这个方法解决了单独记录索引和通过数组对象取得值的问题。不过,没有办法标识迭代何时终止。因此这个方法只适用于数组,而且回调结构也比较笨拙。

在ECMAScript较早的版本中,执行迭代必须使用循环或其他辅助结构。随着代码量增加,代码会变得越发混乱。很多语言都通过原生语言结构解决了这个问题,开发者无须事先知道如何迭代就能实现迭代操作。这个解决方案就是迭代器模式。Python、Java、C++,还有其他很多语言都对这个模式提供了完备的支持。JavaScript在ECMAScript 6以后也支持了迭代器模式。