在 JavaScript 中,咱们常常会看到可迭代对象,迭代器和生成器的概念,它们之间有什么区别和联系呢,我就是想经过这篇文章总结一下,把这个问题搞明白。javascript
Iterable 是指有 [Symbol.iterator]
属性的对象,这个属性 obj[Symbol.iterator]
就是 Iterator(迭代器)。也能够说可迭代对象是实现了 Symbol.iterator
方法的对象。java
可迭代对象能够被 for..of
循环遍历,咱们最常进行迭代操做的可迭代对象就是 Array,其实还有其余可迭代对象,例如 String、Set、Map、函数的 arguments 对象和 NodeList 对象等,这些对象都有默认的 Symbol.iterator
属性。git
Iterator 必须有 next()
方法,它每次返回一个 {done: Boolean, value: any}
对象,这里 done:true
代表迭代结束,不然 value
就是下一个要迭代的值。github
假设咱们 range
对象,咱们但愿对其使用 for..of
循环:segmentfault
let range = {
from: 1,
to: 5
};
// 咱们但愿能够这样:
// for(let num of range) ... num=1,2,3,4,5
复制代码
为了让 range
对象可迭代,咱们须要为对象添加一个名为 Symbol.iterator
的方法。当 for..of
循环启动时,它会调用这个方法(若是没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。今后开始,for..of
仅适用于这个被返回的对象。当 for..of
循环但愿取得下一个数值,它就调用这个对象的 next()
方法。next()
方法返回的结果的格式必须是 {done: Boolean, value: any}
,当 done=true
时,表示迭代结束,不然 value
是下一个值。异步
let range = {
from: 1,
to: 5
};
// for..of 循环首先会调用这个
range[Symbol.iterator] = function() {
// 它返回迭代器对象,接下来 for..of 仅与此迭代器一块儿工做
return {
current: this.from,
last: this.to,
// next() 在 for..of 的每一轮循环迭代中被调用
next() {
// 它将会返回 {done:.., value :...} 格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 如今它能够运行了!
for (let num of range) {
alert(num); // 1, 而后是 2, 3, 4, 5
}
复制代码
请注意可迭代对象的核心功能:关注点分离。range
自身没有 next()
方法。相反,是经过调用 range[Symbol.iterator]()
建立了另外一个对象,即所谓的“迭代器”对象,而且它的 next
会为迭代生成值。所以,迭代器对象和与其进行迭代的对象是分开的。函数
从技术上说,咱们能够将它们合并,并使用 range
自身做为迭代器来简化代码。ui
就像这样:this
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
this.current = this.from;
return this;
},
next() {
if (this.current <= this.to) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
for (let num of range) {
alert(num); // 1, 而后是 2, 3, 4, 5
}
复制代码
如今 range[Symbol.iterator]()
返回的是 range
对象自身:它包括了必需的 next()
方法,并经过 this.current
记忆了当前的迭代进程。这样更短,对吗?是的。有时这样也能够。spa
但缺点是,如今不可能同时在对象上运行两个 for..of
循环了:它们将共享迭代状态,由于只有一个迭代器,即对象自己。可是两个并行的 for..of
是很罕见的,即便在异步状况下。
此外,咱们还能够将 range
设置为 range.to = Infinity
,这时 range
则成为了无穷迭代器。或者咱们能够建立一个可迭代对象,它生成一个无穷伪随机数序列。也是可能的。next
没有什么限制,它能够返回愈来愈多的值,这是正常的。固然,迭代这种对象的 for..of
循环将不会中止。可是咱们能够经过使用 break
来中止它。
Generator 是一个特殊函数,调用返回一个 Generator。
未完待续……
参考: