nop*_*ole 13 javascript iterator iterable ecmascript-6
迭代器与迭代器相同还是不同?
从规范来看,iterable似乎是一个对象,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)
Run Code Online (Sandbox Code Playgroud)
所以在上面的代码中,bar是可迭代的,wah是迭代器,next()是迭代器的接口。
所以,iterable 和 iterator 是不同的东西。
但是,现在在生成器和迭代器的常见示例中:
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
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,gen1是生成器,iter1是迭代器,并且iter1.next()会做适当的工作。但是iter1[Symbol.iterator]确实给出了一个函数,该函数在调用时返回iter1,它是一个迭代器。那么iter1在这种情况下是可迭代的还是迭代器?
此外,iter1与上面的示例1不同,因为示例1中的iterable可以[1, 3, 5]使用 using 多次给出[...bar],而虽然iter1是一个迭代器,但由于它返回自身,每次都是相同的迭代器,因此只会给出[1, 3, 5]一次。
所以我们可以说,对于一个 iterable bar,可以[...bar]给出多少次结果[1, 3, 5]——答案是,这取决于。iterable 和迭代器一样吗?答案是,它们是不同的东西,但是当可迭代对象将自身用作迭代器时,它们可以是相同的。那是对的吗?
是的,迭代器和迭代器是不同的东西,但是大多数迭代器(包括你从 JavaScript 本身获得的所有迭代器,例如来自keys或values方法Array.prototype或来自生成器函数的生成器)继承自%IteratorPrototype% 对象,它有一个Symbol.iterator类似的方法这个:
[Symbol.iterator]() {
return this;
}
Run Code Online (Sandbox Code Playgroud)
结果是所有标准迭代器也是可迭代的。这样你就可以直接使用它们,或者在for-of循环等中使用它们(需要迭代器,而不是迭代器)。
考虑keys数组的方法:它返回一个数组迭代器,它访问数组的键(它的索引,作为数字)。请注意,它返回一个迭代器。但它的一个常见用途是:
for (const index of someArray.keys()) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
for-of需要一个iterable,而不是一个iterator,那为什么会这样呢?
它之所以有效,是因为迭代器也是可迭代的;Symbol.iterator刚刚返回this。
这是我在本书第 6 章中使用的一个示例:如果您想遍历所有条目但跳过第一个条目并且不想使用slice切掉子集,则可以获取迭代器,读取第一个值,然后交给一个for-of循环:
[Symbol.iterator]() {
return this;
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是所有标准迭代器。有时人们会展示手动编码迭代器的示例,如下所示:
for (const index of someArray.keys()) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
rangethere返回的迭代器不是可迭代的,因此当我们尝试将它与for-of.
为了使其可迭代,我们需要:
Symbol.iterator上面答案开头的方法添加到其中,或者遗憾的是,TC39 决定不提供直接获取 %IteratorPrototype% 对象的方法。有一种间接的方法(从数组中获取迭代器,然后获取其原型,其定义为 %IteratorPrototype%),但这很痛苦。
但是无论如何都没有必要像那样手动编写迭代器;只需使用生成器函数,因为它返回的生成器是可迭代的:
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);
}Run Code Online (Sandbox Code Playgroud)
相比之下,并非所有可迭代对象都是迭代器。数组是可迭代的,但不是迭代器。字符串、映射和集合也是如此。
| 归档时间: |
|
| 查看次数: |
522 次 |
| 最近记录: |