[JS] Iterators

以下內容整理自這段影片 Iterators in JavaScript using Quokka

什麼是 iterators ?

為什麼 for…of 可以對 Array 做迭代 ?

Array 提供了 iteratorsfor...of loop,讓 for...of loop 利用 iterators 進行迭代。

那 for…of 又是怎麼得到 iterators ?

要解釋這個,要先岔開說一下 Symbol。
Symbol 是什麼? 影片中解釋它可以看作是一個 unique key。至於詳細的 Symbol.iterator 說明可以參考 MDN Symbol
下面例子裡面的變數 iterator 會回傳一個物件,並且帶有 next 屬性可以執行。這和 generator* 有關,之後會再發一篇有關 generator 說明。
就是因為 iterator 的這個特性,所以和 forEach 不同, for...of 可以對除了 Array 以外的東西進行迭代,String 也可以。只要進行迭代的對象具有 iterator 屬性就可以。

用以下的例子來做說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const dragons = [
'cool dragon',
'angry dragon',
'nasty dragon'
]
Symbol.iterator // Symbol{}
const iterator = dragons[Symbol.iterator]()
iterator // {[Iterator]}

// 下面這段就是 for...of loop 在執行的
iterator.next() // 會得到物件:{value: 'cool dragon', done: false}
iterator.next() // 會得到物件:{value: 'angry dragon', done: false}
iterator.next() // 會得到物件:{value: 'nasty dragon', done: false}
iterator.next() // 會得到物件:{value: 'undefined', done: true}


for(const dragon of dragons){

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 引入 randomNumber
const randomNumber = require('random-number');

function randomItem(array){
const randomIndex = randomNumber({
min: 0,
max: array.length - 1,
integer: true
});
return array[randomIndex];
}
const makeDragon = () => {
const dragonSizes = ['big', 'medium', 'tiny'];
const dragonAbilities = ['fire', 'ice', 'lightning'];
return randomItem(dragonSizes) + ' ' +
randomItem(dranAbilities) + ' ' +
'dragon;
}

makeDragon() // tiny fire dragon 隨機出現不同組合的 dragon

下面這個例子就是直接自己寫一個 for…of 的效果

  • Symbol.iterator 會回傳一個 object,裡面有 next 屬性。
  • 和上面的例子做對照,可以看得比較清楚 iterator 到底是怎麼操作執行的。
  • 真正的 iterator 不會設定一個隨機變數去控制執行的次數。這裡只是說明可以自己設定 iterator 執行的條件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const dragonArmy = {
    [Symbol.iterator]: () => {
    return {
    next: () => {
    const enoughDragonSpawned = Math.random() > 0.75;
    if(!enoughDragonSpawned)
    return {
    value: makeDragon(),
    done: false
    }
    return {done: true}
    }
    }
    }
    }

    for (const dragon of dragonArmy){
    dragon //
    }

小結

  • 可以自己建立想要的 iterators 進行迭代。
  • iterators 也可以是 Asynchronous。
  • generator 之後會再另外提到,它是一個建立 iterators 的語法糖。

參考資料

Iterators in JavaScript using Quokka
很喜歡這個 Youtube 頻道,推薦大家沒事可以看看。