一锤悄、Iterator
1.Iterator(迭代器)的概念
遍歷器(Iterator) 是一種用來處理所有不同的數(shù)據(jù)結(jié)構(gòu)的機(jī)制。它是一種接口嘉抒,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制零聚。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。
JavaScript 表示“集合”的數(shù)據(jù)結(jié)構(gòu)
- Array
- Object
- Map (ES6新增)
- Set (ES6新增)
Iterator 的作用
- 為各種數(shù)據(jù)結(jié)構(gòu)隶症,提供一個(gè)統(tǒng)一的政模、簡(jiǎn)便的訪問接口;
- 使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列蚂会;
- ES6 創(chuàng)造了一種新的遍歷命令
for...of
循環(huán)淋样,Iterator 接口主要供for...of
消費(fèi)。
Iterator 的遍歷過程
創(chuàng)建一個(gè)指針對(duì)象胁住,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置趁猴。也就是說,遍歷器對(duì)象本質(zhì)上彪见,就是一個(gè)指針對(duì)象儡司。
第一次調(diào)用指針對(duì)象的
next
方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員余指。第二次調(diào)用指針對(duì)象的
next
方法捕犬,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個(gè)成員。不斷調(diào)用指針對(duì)象的
next
方法酵镜,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置或听。
每一次調(diào)用
next
方法,都會(huì)返回?cái)?shù)據(jù)結(jié)構(gòu)的當(dāng)前成員的信息笋婿。具體來說,就是返回一個(gè)包含value
和done
兩個(gè)屬性的對(duì)象顿颅。其中:
value
屬性:當(dāng)前成員的值done
屬性:一個(gè)布爾值缸濒,表示遍歷是否結(jié)束。
2.迭代器協(xié)議
迭代器協(xié)議 定義了產(chǎn)生一系列值(無論是有限個(gè)還是無限個(gè))的標(biāo)準(zhǔn)方式粱腻。當(dāng)值為有限個(gè)時(shí)庇配,所有的值都被迭代完畢后,則會(huì)返回一個(gè)默認(rèn)返回值绍些。
只有實(shí)現(xiàn)了一個(gè)擁有以下語義的 next()
方法捞慌,一個(gè)對(duì)象才能成為迭代器:
next()方法:是一個(gè)無參數(shù)函數(shù),返回一個(gè)擁有
done
和value
兩個(gè)屬性的對(duì)象柬批。done(boolean):如果迭代器可以產(chǎn)生序列中的下一個(gè)值啸澡,則為
false
。如果迭代器已將序列迭代完畢氮帐,則為true
嗅虏。這種情況下,value
是可選的上沐,如果它依然存在皮服,即為迭代結(jié)束之后的默認(rèn)返回值。value:迭代器返回的任何 JavaScript 值。done 為 true 時(shí)可省略龄广。
注意:
next()
方法必須返回一個(gè)對(duì)象硫眯,該對(duì)象應(yīng)當(dāng)有兩個(gè)屬性:done
和value
,如果返回了一個(gè)非對(duì)象值(比如false
或undefined
)择同,則會(huì)拋出一個(gè)TypeError
異常("iterator.next() returned a non-object value"
)两入。
3.可迭代協(xié)議
可迭代協(xié)議 允許 JavaScript 對(duì)象定義或定制它們的迭代行為,例如奠衔,在一個(gè)
for..of
結(jié)構(gòu)中谆刨,哪些值可以被遍歷到。一些內(nèi)置類型同時(shí)是內(nèi)置可迭代對(duì)象
或者Map
而其他內(nèi)置類型則不是(比如Object
)归斤。
要成為可迭代對(duì)象痊夭, 一個(gè)對(duì)象必須實(shí)現(xiàn) @@iterator
方法。
-
[Symbol.iterator] :返回一個(gè)符合
迭代器協(xié)議
的對(duì)象的無參數(shù)函數(shù)脏里。
當(dāng)一個(gè)對(duì)象需要被迭代的時(shí)候(比如被置入一個(gè) for...of
循環(huán)時(shí))她我,首先,會(huì)不帶參數(shù)調(diào)用它的 @@iterator
方法迫横,然后使用此方法返回的 迭代器 獲得要迭代的值番舆。
值得注意的是調(diào)用此零個(gè)參數(shù)函數(shù)時(shí),它將作為對(duì)可迭代對(duì)象的方法進(jìn)行調(diào)用矾踱。 因此恨狈,在函數(shù)內(nèi)部,this
關(guān)鍵字可用于訪問可迭代對(duì)象的屬性呛讲,以決定在迭代過程中提供什么禾怠。
此函數(shù)可以是普通函數(shù),也可以是生成器函數(shù)贝搁,以便在調(diào)用時(shí)返回迭代器對(duì)象吗氏。 在此生成器函數(shù)的內(nèi)部,可以使用 yield
提供每個(gè)條目雷逆。
4.實(shí)現(xiàn)一個(gè)滿足迭代器協(xié)議與可迭代協(xié)議的對(duì)象
var letters= {
cursor: 0,
next () {
const actions = ['A', 'B', 'C', 'D']
if (this.cursor > 7) {
return {
done: true
}
}
return {
done: false,
value: actions[this.cursor++ % actions.length]
}
},
[Symbol.iterator]: function () {
return this
}
}
// 實(shí)現(xiàn)后可用for…of遍歷
for (let item of letters) {
console.log('item:::', item) // done 為 true 時(shí) 不執(zhí)行value中的語句
}
// 輸出結(jié)果:
// item::: A
// item::: B
// item::: C
// item::: D
// item::: A
// item::: B
// item::: C
// item::: D
5.為什么需要2個(gè)協(xié)議
- 因?yàn)椴豢赡苤酪粋€(gè)特定的對(duì)象是否實(shí)現(xiàn)了迭代器協(xié)議弦讽,然而創(chuàng)造一個(gè)同時(shí)滿足迭代器協(xié)議和可迭代協(xié)議的對(duì)象是很容易的(就像上面的栗子所示)。這樣做允許一個(gè)迭代器能被不同希望迭代的語法方式所使用膀哲。 因此往产,很少只實(shí)現(xiàn)迭代器協(xié)議而不實(shí)現(xiàn)可迭代協(xié)議。
6.實(shí)現(xiàn)了迭代器協(xié)議與可迭代協(xié)議的語法或特性
Array
Set
Map
generator
7.使用了迭代器協(xié)議與可迭代協(xié)議的語法或特性
for...of...
...
Array.from()