PJCHENder 未整理筆記

[JS] JavaScript 疊代器(Iterator)

2017-09-26

[JS] JavaScript 疊代器(Iterator)

@(Javascript)[ES6, JavaScript]

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Iterator 可以透過 Symbol.iterator 來客制化疊代的方式
* 裡面會包含 next function,這個 function 會回傳 value 和 done
* 像這樣:
**/

next () {
return index < arr.length {
value: <value>,
done: <true|false>
}
}

觀念

  • 在 ES6 中,有三類數據結構原生具備 Iterator 接口:ArrayArray-like ObjectSetMap 結構
  • 除此之外,其他數據結構(主要是物件)的 Iterator 接口,都需要自己在 Symbol.iterator 屬性上面部署,這樣才會被 for...of 迴圈遍歷。
  • iterator 會返回 value(當前成員的值) 和 done(Boolean,表示是否遍歷結束)

基本使用

Symbol 時有提到 JS 中有內建的 Symbol,大部分是提供內建的函式方法(Well-known Symbols),其中 Symbol.iterator 就是裡面內的 Symbol,對於可疊代的型別,在 Symbol.iterator 中就有提供函式可以讓它在 for...of 時使用。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Demonstrate an iterator
**/

let arr = [1, 2, 3]
console.log(typeof arr[Symbol.iterator]) // function

let current = arr[Symbol.iterator]()
current.next() // Object {value: 1, done: false}
current.next() // Object {value: 2, done: false}
current.next() // Object {value: 3, done: false}
current.next() // Object {value: undefined, done: true}

模擬 iterator 的 function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Create a function to simulate iterator
**/
var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}

搭配 for…of,客制化自己的 iterator

for...of 在當 Iterator 的 donetrue 時就不再疊代。

Array 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Create a custom iterable array
**/
arr[Symbol.iterator] = function() {
let nextIndex = 0
return {
next() {
return nextIndex < arr.length ? {
value: arr[nextIndex++] * 2,
done: false
} : {
value: undefined,
done: true
};
}
}
}
for (item of arr) {
// 當 done 為 true 時就不在疊代
console.log(item) // 2, 4, 6
}

物件部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Create a custom iterable Object
**/

let person = {
firstName: 'Aaron',
lastName: 'Chen',
hobbies: ['computer', 'programming', 'sports'],
// 讓 JS 知道這個物件具有 iterator,所以是 iterable
[Symbol.iterator]: function() {
let index = 0
let hobbies = this.hobbies
return {
next() {
return index < hobbies.length ? {
done: false,
value: hobbies[index++]
} : {
done: true,
value: undefined
}
}
}
}
}

for (let hobby of person) {
console.log(hobby) // computer, programming, spots
}

Demo Code

ES6 Iterator @ PJCHENder JSFiddle

參考資料

掃描二維條碼,分享此文章