一、 概念
? ? ? ?JavaScript原有表示“集合”的數(shù)據(jù)結(jié)構(gòu),主要是數(shù)組(' Array ')和對象('?Object ' ),ES6又添加了Map和Set。這樣就有了四種數(shù)據(jù)集合,用戶還可以組合使用它們,定義自己的數(shù)據(jù)結(jié)構(gòu),比如數(shù)組的成員是Map,Map的成員是對象。這樣就需要一種統(tǒng)一的接口機制,來處理不同的數(shù)據(jù)結(jié)構(gòu)。
? ? ? ?遍歷器(Iterator)就是這樣一種機制。它是一種接口,為不同的數(shù)據(jù)結(jié)構(gòu)提供一種訪問機制,即for ... of 循環(huán)。當使用for...of
循環(huán)遍歷某種數(shù)據(jù)結(jié)構(gòu)時,該循環(huán)會自動去尋找 Iterator 接口。任何數(shù)據(jù)結(jié)構(gòu)只要部署Iterator接口,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。
二、本質(zhì)?
? ? ? ? 迭代器對象本質(zhì)上,就是一個指針對象。通過指針對象的next(), 用來移動指針。
? ? ? ? 迭代器協(xié)議:對象必須提供一個next(),執(zhí)行該方法要么返回迭代的下一項,要么就引起Stopiteration異常,以終止迭代。
? ? ? ? 每調(diào)用一次next ()方法,都會返回一個對象,都會返回數(shù)據(jù)結(jié)構(gòu)的當前成員的信息。這個對象有 value 和 done 兩個屬性,value屬性返回當前位置的成員,done屬性是一個布爾值,表示遍歷是否結(jié)束,即是否有必要再調(diào)用一次next () 。對于遍歷器來說,value:undefined和done:false屬性都是可以省略的。
? ? ? ??ES6 規(guī)定,默認的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性上;或者說,一個數(shù)據(jù)結(jié)構(gòu)只要有Symbol.iterator屬性,就認為是可遍歷的。
三、實現(xiàn)Iterator接口的原生對象
原生具備Iterator接口的數(shù)據(jù)結(jié)構(gòu)有:
- Array
- Map
- Set
- String
- TypedArray
- 函數(shù)的 arguments 對象
- NodeList 對象
?可以看到Array原型對象已經(jīng)實現(xiàn)了Iterator這個屬性:
?那么數(shù)組的實例對象也擁有這個屬性,可以調(diào)用試試:
下面是模擬next()方法返回的例子:
? ? ? ?上面的代碼定義了一個makeIterator函數(shù),它是一個遍歷器生成的函數(shù),作用就是返回一個遍歷器對象。對數(shù)組[ ’a', 'b' ]執(zhí)行這個函數(shù),就會返回該數(shù)組的遍歷器對象(指針對象)it。指針對象的next
方法,用來移動指針。開始時,指針指向數(shù)組的開始位置。然后,每次調(diào)用next
方法,指針就會指向數(shù)組的下一個成員。第一次調(diào)用,指向a
;第二次調(diào)用,指向b
。
? ? ? ??總之,調(diào)用指針對象的next()方法,就可以遍歷事先給定的數(shù)據(jù)結(jié)構(gòu)。
? ? ? ? 上面說了,對于遍歷器對象來說, done:false 和 value:undefined屬性都是可以省略的,因此上面的makeIterator
函數(shù)可以簡寫成下面的形式。
?使用場合:
①?對實現(xiàn)了Iterator接口的數(shù)據(jù)解構(gòu)賦值
?② 擴展運算符
上面代碼的擴展運算符內(nèi)部就調(diào)用 Iterator 接口。
實際上,這提供了一種簡便機制,可以將任何部署了 Iterator 接口的數(shù)據(jù)結(jié)構(gòu),轉(zhuǎn)為數(shù)組。也就是說,只要某個數(shù)據(jù)結(jié)構(gòu)部署了 Iterator 接口,就可以對它使用擴展運算符,將其轉(zhuǎn)為數(shù)組。
三、 for... of 循環(huán)
for...of
循環(huán)可以使用的范圍包括數(shù)組、Set 和 Map 結(jié)構(gòu)、某些類似數(shù)組的對象(比如arguments
對象、DOM NodeList 對象)、字符串等。
數(shù)組原生具備iterator接口,(默認部署Symbol.iterator屬性),for...of 循環(huán)本質(zhì)上就是調(diào)用這個接口產(chǎn)生的遍歷器:
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
for(let v of obj) {
console.log(v); // red green blue
}
上面代碼中,空對象obj
部署了數(shù)組arr
的Symbol.iterator
屬性,結(jié)果obj
的for...of
循環(huán),產(chǎn)生了與arr
完全一樣的結(jié)果。
for ... of 循環(huán)可以代替數(shù)組實例 forEach 方法。
const arr = ['red', 'green', 'blue'];
arr.forEach(function (element, index) {
console.log(element); // red green blue
console.log(index); // 0 1 2
});
JavaScript 原有的for...in
循環(huán),只能獲得對象的鍵名,不能直接獲取鍵值。ES6 提供for...of
循環(huán),允許遍歷獲得鍵值。
var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
for (let a of arr) {
console.log(a); // a b c d
}
四、 Set 和 Map結(jié)構(gòu)
Set和Map結(jié)構(gòu)也原生具有Interator接口,可以直接使用for...of循環(huán)。
var engines = new Set(['1','2','3']);
for (var e of engines) {
console.log(e); // 1 2 3
}
var class = new Map();
class .set('Tom', 12);
class .set('Lala', 13);
class .set('9300', 14);
for (var [name,value] of class) {
console.log(name + ':' + number); // Tom:12 Lala:13 9300:14
}
以上代碼演示了如何遍歷Set和Map結(jié)構(gòu)。需要注意的是,首先遍歷的順序是按照哥哥成員被添加進數(shù)據(jù)結(jié)構(gòu)的順序。其次,Set結(jié)構(gòu)遍歷時,返回的是一個值。而Map結(jié)構(gòu)遍歷時,返回的是一個數(shù)組,該數(shù)組的兩個成員分別是當前Map成員的鍵名和鍵值。文章來源:http://www.zghlxwxcb.cn/news/detail-469555.html
let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
console.log(pair);
}
// ['a', 1]
// ['b', 2]
for (let [key, value] of map) {
console.log(key + ' : ' + value);
}
// a : 1
// b : 2
其他內(nèi)容可參照?ES6入門文章來源地址http://www.zghlxwxcb.cn/news/detail-469555.html
到了這里,關(guān)于JS - iterator(迭代器)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!