# 十、迭代器

迭代器是可以遍历集合的对象。它们支持像。NET CLR `IEnumerable`或 Java `Iterable`对象。他们可以用`for..of`将`for..in`推广到基于自定义迭代器的迭代。它们也不需要实现数组，因此支持像 LINQ 这样的懒惰设计模式。

下面是一个产生斐波那契数的迭代器定义的例子:

代码清单 137

```js
  let fibonacci = {
    [Symbol.iterator]() {
      let
  pre = 0,
  cur = 1;
      return
  {
        next() {
          [pre, cur] = [cur, pre +
  cur];
          return
  { done: false,
  value: cur }
        }
      }
    }
  }

```

首先要注意的是`Symbol.iterator`的用法。定义迭代器时，这个关键字是必需的。基于该接口，您会注意到迭代器返回一个函数`next`。有趣的是，在`next`函数内部，我们看到了破坏的例子。这比在多个语句中编写等价语句更方便。最后，我们看到`next`函数返回一个具有两个属性的对象文字。

让我们转到下一节，看看这个迭代器是如何使用的。

现在我们已经定义了一个迭代器，让我们看看如何使用它。考虑下面的代码示例:

代码清单 138

```js
  for (var n of fibonacci) {
    //
  truncate the sequence at 100
    if
  (n > 100)
      break;
    console.log(n);
  }

```

可以看到`for..of`的语法和`for..in`是一样的。我们缩短了序列，这样我们就可以显示输出，而不用填满整个页面。以下是我们执行上述代码时的输出:

代码清单 139

```js
  1
  2
  3
  5
  8
  13
  21
  34
  55
  89

```

让我们看另一个使用带数组的`for..of`的例子:

代码清单 140

```js
  for (let element of [1,
  2, 3])
  {
    console.log(element);
  }

```

前面的代码也可以编写如下:

代码清单 141

```js
  let elements = [1, 2, 3];
  for (let element of elements) {
    console.log(element);
  }

```

以下是前面代码的输出:

代码清单 142

```js
  1
  2
  3

```

当我们比较`for..of`和`for..in`时，我们会看到`for..in`迭代属性名而`for..of`迭代属性值。

让我们通过查看`String`的内置 iterable 来进一步了解迭代器。考虑以下代码:

代码清单 143

```js
  let someString = "hi";
  var iterator = someString[Symbol.iterator]();
  console.log(iterator + "");

  console.log(iterator.next());
  console.log(iterator.next());
  console.log(iterator.next());

```

这里，我们正在创建一个字符串变量`someString`，它包含字符串`hi`。接下来，我们使用`Symbol.iterator`语法从`someString`变量创建一个迭代器。最后，我们注销迭代器。我们通过连接一个空字符串来强迫它使用`toString`函数。`iterator.next()`的调用序列向我们展示了返回的对象文字中包含的内容。

以下是前面代码的输出:

代码清单 144

```js
  [object String Iterator]
  { value: 'h', done: false }
  { value: 'i', done: false }
  { value: undefined, done: true }

```

如您所见，这与我们在自定义斐波那契迭代器中实现的签名相同。希望这能让你更好地理解迭代器是如何工作的。