可迭代与迭代器相同,还是不同?
[似乎,from the specifications,一个可迭代对象是一个对象,例如,obj
,因此obj[Symbol.iterator]
引用了一个函数,因此,当调用该函数时,它返回一个对象,该对象具有一个next
方法,该方法可以返回一个{value: ___, done: ___}
对象:
function foo() {
let i = 0;
const wah = {
next: function() {
if (i <= 2) return { value: (1 + 2 * i++), done: false }
else return { value: undefined, done: true }
}
};
return wah; // wah is iterator
}
let bar = {} // bar is iterable
bar[Symbol.iterator] = foo;
console.log([...bar]); // [1, 3, 5]
for (a of bar) console.log(a); // 1 3 5 (in three lines)
因此在上面的代码中,bar
是可迭代的,wah
是迭代器,next()
是迭代器接口。
因此,可迭代和迭代器是不同的东西。
但是,现在在生成器和迭代器的常见示例中:
function* gen1() {
yield 1;
yield 3;
yield 5;
}
const iter1 = gen1();
console.log([...iter1]); // [1, 3, 5]
for (a of iter1) console.log(a); // nothing
const iter2 = gen1();
for (a of iter2) console.log(a); // 1 3 5 (in three lines)
console.log(iter1[Symbol.iterator]() === iter1); // true
在上述情况下,gen1
是生成器,iter1
是迭代器,并且iter1.next()
将做适当的工作。但是iter1[Symbol.iterator]
确实提供了一个函数,该函数在调用时会返回iter1
,它是一个迭代器。那么在这种情况下iter1
既是可迭代的,又是迭代器?
[此外,iter1
与上面的示例1不同,因为示例1中的可迭代项可以使用[1, 3, 5]
给出[...bar]
所需的次数,而iter1
是可迭代项,但是由于它返回了自身,每次都是相同的迭代器,只会给出[1, 3, 5]
一次。
所以我们可以说,一个可迭代的[...bar]
可以给出结果[1, 3, 5]
多少次-答案取决于。并且可迭代与迭代器相同吗?答案是,它们是不同的东西,但是当可迭代对象将自身用作迭代器时,它们可以是相同的。正确吗?
是,iterables和迭代器是不同的东西,但是大多数迭代器(包括从JavaScript本身获得的所有迭代器,例如生成器函数的生成器)都从%IteratorPrototype% object继承,像这样的Symbol.iterator
方法:
[Symbol.iterator]() {
return this;
}
结果是所有标准迭代器也是可迭代的。这样一来,您可以直接使用它们,也可以在for-of
循环等中使用它们(它们期望可迭代,而不是迭代器)。
考虑数组的keys
方法:它返回一个访问数组键(其索引为数字)的数组迭代器。请注意,它返回一个iterator。但是它的常见用法是:
for (const index of someArray.keys() {
// ...
}
[for-of
需要一个可迭代,而不是一个迭代器,那为什么行得通呢?
之所以有效,是因为迭代器也是可迭代的; Symbol.iterator
仅返回this
。
这是我在本书的第6章中使用的示例:如果您想遍历所有条目但跳过第一个条目,并且不想使用slice
分割子集,则可以获取迭代器,读取第一个值,然后切换到for-of
循环:
const a = ["one", "two", "three", "four"];
const it = a[Symbol.iterator]();
// Skip the first one
it.next();
// Loop through the rest
for (const value of it) {
console.log(value);
}
相反,并不是所有的迭代器都是迭代器。数组是可迭代的,但不是迭代器。字符串,地图和集合也是如此。