Logo
Section 1 / 12

可迭代对象与迭代器

JavaScript 中可迭代对象与迭代器及其行为简介

导入

可迭代对象与迭代器

JavaScript 中可迭代对象与迭代器及其行为简介

现在我们已经介绍了 for...of 循环和符号,可以轻松地讨论迭代器了。

了解迭代器是非常值得的,特别是如果你喜欢惰性求值,或者希望能够描述无限序列。理解迭代器也有助于你更好地掌握生成器、Promise、Set 和 Map。

在掌握了迭代器的基础知识后,我们将运用这些知识来理解生成器的工作原理。

ES6 引入了 可迭代协议。该协议定义了 JavaScript 对象的遍历行为。

一个 可迭代对象 拥有一个键为 Symbol.iterator 的迭代方法。该方法返回一个 迭代器对象。

1let iterableObject = { 2 [Symbol.iterator]() { return iteratorObject; } 3};

Symbol.iterator 是一个 公认的符号。接下来我们将使用 Symbol.iterator 来描述可迭代对象。请注意,这里使用这种写法只是为了帮助理解迭代器的工作机制。实际上,在你的代码中几乎不会直接用到 Symbol.iterator。很快你就会学到另一种定义可迭代对象的方法。

一个 迭代器对象 是一种具有 next 方法的数据结构。调用该方法时,它会返回下一个元素,并附带一个布尔值,用于指示是否已到达迭代的末尾。

1// 在 iterableObject 之前放置以下代码 2let iteratorObject = { 3 next() { 4 return { 5 done: true, 6 value: null 7 }; 8 } 9};

next 函数的返回值包含两个属性:

  • done 被视为布尔值。当 done 为 true 时,表示迭代结束,此时 value 不再参与迭代。
  • value 是下一次迭代的值。只有当 done 为 false 时,value 才会被视为迭代的一部分。当 done 为 true 时,value 就成为迭代器的返回值。

让我们以一个倒计时对象为例:

1let countdownIterator = { 2 countdown: 10, 3 next() { 4 this.countdown -= 1; 5 return { 6 done: this.countdown === 0, 7 value: this.countdown 8 }; 9 } 10}; 11 12let countdownIterable = { 13 [Symbol.iterator]() { 14 return Object.assign({}, countdownIterator); 15 } 16}; 17 18let iterator = countdownIterable[Symbol.iterator](); 19 20console.log(iterator.next()); 21//> Object {done: false, value: 9} 22 23console.log(iterator.next()); 24//> Object {done: false, value: 8}

注意,迭代的状态被保留了下来。

Object.assign 的作用是:每次可迭代对象返回迭代器时,都会创建一个迭代器对象的浅拷贝。这使得同一个可迭代对象可以拥有多个独立的迭代器,每个迭代器都保存自己的内部状态。如果没有 Object.assign,那么多个迭代器将只是指向同一个迭代器对象。考虑下面这段代码:

1let secondIterator = countdownIterable[Symbol.iterator](); 2let thirdIterator = countdownIterable[Symbol.iterator](); 3 4console.log(secondIterator.next()); 5//> Object {done: false, value: 9} 6 7console.log(thirdIterator.next()); 8//> Object {done: false, value: 9} 9 10console.log(secondIterator.next()); 11//> Object {done: false, value: 8}

现在我们来学习如何使用迭代器和可迭代对象。

集合、映射及其弱引用版本

消费可迭代对象