Iterable,Iterator,Generator 三者的区别与联系
在 JavaScript 中,我们经常会看到可迭代对象,迭代器和生成器的概念,它们之间有什么区别和联系呢,我就是想通过这篇文章总结一下,把这个问题搞明白。
Interable(可迭代对象)
Iterable 是指有 [Symbol.iterator]
属性的对象,这个属性 obj[Symbol.iterator]
就是 Iterator(迭代器)。也可以说可迭代对象是实现了 Symbol.iterator
方法的对象。
可迭代对象可以被 for..of
循环遍历,我们最常进行迭代操作的可迭代对象就是 Array,其实还有其他可迭代对象,例如 String、Set、Map、函数的 arguments 对象和 NodeList 对象等,这些对象都有默认的 Symbol.iterator
属性。
Iterator(迭代器)
Iterator 必须有 next()
方法,它每次返回一个 {done: Boolean, value: any}
对象,这里 done:true
表明迭代结束,否则 value
就是下一个要迭代的值。
手写实现一个 Iterator
假设我们 range
对象,我们希望对其使用 for..of
循环:
let range = { |
为了让 range
对象可迭代,我们需要为对象添加一个名为 Symbol.iterator
的方法。当 for..of
循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。从此开始,for..of
仅适用于这个被返回的对象。当 for..of
循环希望取得下一个数值,它就调用这个对象的 next()
方法。next()
方法返回的结果的格式必须是 {done: Boolean, value: any}
,当 done=true
时,表示迭代结束,否则 value
是下一个值。
let range = { |
请注意可迭代对象的核心功能:关注点分离。range
自身没有 next()
方法。相反,是通过调用 range[Symbol.iterator]()
创建了另一个对象,即所谓的“迭代器”对象,并且它的 next
会为迭代生成值。因此,迭代器对象和与其进行迭代的对象是分开的。
从技术上说,我们可以将它们合并,并使用 range
自身作为迭代器来简化代码。
就像这样:
let range = { |
现在 range[Symbol.iterator]()
返回的是 range
对象自身:它包括了必需的 next()
方法,并通过 this.current
记忆了当前的迭代进程。这样更短,对吗?是的。有时这样也可以。
但缺点是,现在不可能同时在对象上运行两个 for..of
循环了:它们将共享迭代状态,因为只有一个迭代器,即对象本身。但是两个并行的 for..of
是很罕见的,即使在异步情况下。
无穷迭 Interator
此外,我们还可以将 range
设置为 range.to = Infinity
,这时 range
则成为了无穷迭代器。或者我们可以创建一个可迭代对象,它生成一个无穷伪随机数序列。也是可能的。next
没有什么限制,它可以返回越来越多的值,这是正常的。当然,迭代这种对象的 for..of
循环将不会停止。但是我们可以通过使用 break
来停止它。
Generator
Generator 是一个特殊函数,调用返回一个 Generator。
未完待续……
参考:
- 本文链接:https://www.dingxuewen.com/article/iterable-iterator-and-generator-of-javascript/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!