JavaScript 中 Iterable,Iterator,Generator 三者的區別與聯繫

在 JavaScript 中,咱們常常會看到可迭代對象,迭代器和生成器的概念,它們之間有什麼區別和聯繫呢,我就是想經過這篇文章總結一下,把這個問題搞明白。javascript

Interable(可迭代對象)

Iterable 是指有 [Symbol.iterator] 屬性的對象,這個屬性 obj[Symbol.iterator] 就是 Iterator(迭代器)。也能夠說可迭代對象是實現了 Symbol.iterator 方法的對象。java

可迭代對象能夠被 for..of 循環遍歷,咱們最常進行迭代操做的可迭代對象就是 Array,其實還有其餘可迭代對象,例如 String、Set、Map、函數的 arguments 對象和 NodeList 對象等,這些對象都有默認的 Symbol.iterator 屬性。git

Iterator(迭代器)

Iterator 必須有 next() 方法,它每次返回一個 {done: Boolean, value: any} 對象,這裏 done:true 代表迭代結束,不然 value 就是下一個要迭代的值。github

手寫實現一個 Iterator

假設咱們 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 是很罕見的,即便在異步狀況下。

無窮迭 Interator

此外,咱們還能夠將 range 設置爲 range.to = Infinity,這時 range 則成爲了無窮迭代器。或者咱們能夠建立一個可迭代對象,它生成一個無窮僞隨機數序列。也是可能的。next 沒有什麼限制,它能夠返回愈來愈多的值,這是正常的。固然,迭代這種對象的 for..of 循環將不會中止。可是咱們能夠經過使用 break 來中止它。

Generator

Generator 是一個特殊函數,調用返回一個 Generator。

未完待續……

參考:

相關文章
相關標籤/搜索