迭代器是可以遍历集合的对象。它们支持像。NET CLR IEnumerable
或 Java Iterable
对象。他们可以用for..of
将for..in
推广到基于自定义迭代器的迭代。它们也不需要实现数组,因此支持像 LINQ 这样的懒惰设计模式。
下面是一个产生斐波那契数的迭代器定义的例子:
代码清单 137
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
for (var n of fibonacci) {
//
truncate the sequence at 100
if
(n > 100)
break;
console.log(n);
}
可以看到for..of
的语法和for..in
是一样的。我们缩短了序列,这样我们就可以显示输出,而不用填满整个页面。以下是我们执行上述代码时的输出:
代码清单 139
1
2
3
5
8
13
21
34
55
89
让我们看另一个使用带数组的for..of
的例子:
代码清单 140
for (let element of [1,
2, 3])
{
console.log(element);
}
前面的代码也可以编写如下:
代码清单 141
let elements = [1, 2, 3];
for (let element of elements) {
console.log(element);
}
以下是前面代码的输出:
代码清单 142
1
2
3
当我们比较for..of
和for..in
时,我们会看到for..in
迭代属性名而for..of
迭代属性值。
让我们通过查看String
的内置 iterable 来进一步了解迭代器。考虑以下代码:
代码清单 143
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
[object String Iterator]
{ value: 'h', done: false }
{ value: 'i', done: false }
{ value: undefined, done: true }
如您所见,这与我们在自定义斐波那契迭代器中实现的签名相同。希望这能让你更好地理解迭代器是如何工作的。