在 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。
未完待續……
參考: