iterator是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。
iterator 的作用有三個(gè):
一是為各種數(shù)據(jù)結(jié)構(gòu),提供一個(gè)統(tǒng)一的、簡(jiǎn)便的訪問接口;
二是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;
三遍歷命令for...of循環(huán)
Iterator 的遍歷過程
(1)創(chuàng)建一個(gè)指針對(duì)象,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置。
(2)第一次調(diào)用指針對(duì)象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員。
(3)第二次調(diào)用指針對(duì)象的next方法,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個(gè)成員。
(4)不斷調(diào)用指針對(duì)象的next方法,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置。
var it = makeIterator(['a', 'b']);
it.next() // { value: "a" }
it.next() // { value: "b"}
it.next() // { done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true};
}
};
}
let myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
}
[...myIterable] // [1, 2, 3]
默認(rèn) Iterator 接口
原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)如下,即具有Symbol.iterator屬性;
- Array
- Map
- Set
- String
- TypedArray
- 函數(shù)的 arguments 對(duì)象
- NodeList 對(duì)象
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
有了遍歷器接口,數(shù)據(jù)結(jié)構(gòu)就可以用for...of循環(huán)遍歷(詳見下文),也可以使用while循環(huán)遍歷。
調(diào)用 Iterator 接口的場(chǎng)合
一些場(chǎng)合會(huì)默認(rèn)調(diào)用 Iterator 接口(即Symbol.iterator方法)
解構(gòu)賦值
對(duì)數(shù)組和 Set 結(jié)構(gòu)進(jìn)行解構(gòu)賦值時(shí),會(huì)默認(rèn)調(diào)用Symbol.iterator方法。
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符(...)也會(huì)調(diào)用默認(rèn)的 Iterator 接口
var str = 'hello';
[...str] // ['h','e','l','l','o']
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
只要某個(gè)數(shù)據(jù)結(jié)構(gòu)部署了 Iterator 接口,就可以對(duì)它使用擴(kuò)展運(yùn)算符,將其轉(zhuǎn)為數(shù)組
let arr = [...iterable];
yield*
yield*后面跟的是一個(gè)可遍歷的結(jié)構(gòu),它會(huì)調(diào)用該結(jié)構(gòu)的遍歷器接口
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
其他
數(shù)組的遍歷會(huì)調(diào)用遍歷器接口,任何接受數(shù)組作為參數(shù)的場(chǎng)合,其實(shí)都調(diào)用了遍歷器接口。
字符串的 Iterator 接口
var someString = "hi";
typeof someString[Symbol.iterator]
// "function"
var iterator = someString[Symbol.iterator]();
iterator.next() // { value: "h", done: false }
iterator.next() // { value: "i", done: false }
iterator.next() // { value: undefined, done: true }
用Generator 函數(shù) 實(shí)現(xiàn)Iterator 接口
let myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
}
[...myIterable] // [1, 2, 3]