迭代器是咱們咱們平時接觸不少的一個特性es6
當咱們遍歷數組、字符串或者使用解構賦值、對象展開運算符時都會用到迭代器協議相關內容數組
顧名思義,就是讓對象支持被迭代的協議promise
當咱們執行如下代碼時,能夠明確知道什麼值能夠被循環獲得異步
let a = [1,2,3]
for(let i of a) {
console.log(i) // 1,2,3
}
複製代碼
如何支持可迭代協議呢?
對象(或者它原型鏈上的某個對象)必須有一個名字是 Symbol.iterator 的屬性async
Symbol.iterator : 提供一個無參函數, 返回的對象實現迭代器協議函數
迭代器協議定義瞭如何產生和返回迭代器函數的結果測試
實現迭代器協議的對象至少應該包含一個next方法ui
next方法:
提供一個對象的無參函數,返回的對象擁有兩個屬性:
done: boolean 不提供則默認是false
value: 用於迭代時獲取的對象this
驗證迭代對象中的next方法spa
let a = [1,2,3]
var aIt = a[Symbol.iterator]()
aIt.next()
//{value: 1, done: false}
aIt.next()
//{value: 2, done: false}
aIt.next()
//{value: 3, done: false}
aIt.next()
//{value: undefined, done: true}
複製代碼
next方法用於依次返回用於迭代的對象,咋一看,這不就是 generator的next方法嗎
var c={a:1,1:2,c:4,b:5}
for(let i of c) {
console.log(c)
}
//Uncaught TypeError: c is not iterable at <anonymous>:2:14
複製代碼
接下里咱們按照上述協議內容將c對象擴展成支持for...of遍歷, 首先實現可迭代協議 即爲對象添加Symbol.iterator屬性
c[Symbol.iterator] = function(){
return {}
}
複製代碼
如何實現迭代器協議? 即在return中返回包含next方法的對象
c[Symbol.iterator] = function(){
return {
_i:0,
next() {
let keys = Object.keys(c)
if(this._i<keys.length){
console.log("調用iterator-next:"+i)
return {value: keys[this._i++],done: false}
}else {
return {done: true, value:undefined}
}
}
}
}
複製代碼
測試調用
for(let i of c){console.log(i)}
//1 a c b
複製代碼
注: 以上實現中 next方法 this對象指向的是next返回對象
var c={a:1,1:2,c:4,b:5}
function* ci() {
let keys = Object.keys(c),i=0
while(i<keys.length){
yield keys[i++]
}
}
c[Symbol.iterator] = ci
複製代碼
調用測試
for(let i of c){console.log(i)}
// 1 a c b
複製代碼
爲何能夠使用generator實現
1.(MDN)調用一個生成器函數並不會立刻執行它裏面的語句,而是返回一個這個生成器的 迭代器 (iterator )對象。當這個迭代器的 next() 方法被首次(後續)調用時,其內的語句會執行到第一個(後續)出現yield的位置爲止,yield 後緊跟迭代器要返回的值。或者若是用的是 yield*(多了個星號),則表示將執行權移交給另外一個生成器函數(當前生成器暫停執行)
2. cig = new ci()// generator對象。 cig[Symbol.iterator]().next === cig.next
Object.prototype[Symbol.iterator] = function(){
var i=0;
return {next:() =>{
var keys = Object.keys(this)
if(i< keys.length){
return {value: keys[i++],done:false}
}else{
return {done: true}
}
}
}
}
複製代碼
測試
var a = {b:1}
for(let i of a){console.log(i)}
// b
for(let i in a){console.log(i)}
// b
複製代碼
let a = [1,2,3]
for(let i of a) {
console.log(i)
}
//1
//2
//3
複製代碼
var b = {a:1,1:2,c:4,b:5}
[...b]
// Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
複製代碼
而對上面咱們修改的對象C執行如下代碼
[...c]
// ["1", "a", "c", "b"]
複製代碼
function* a(){
yield* c
}
var ac = a()
ac.next()
//{value: "1", done: false}
ac.next()
//{value: "a", done: false}
ac.next()
//{value: "c", done: false}
ac.next()
//{value: "b", done: false}
ac.next()
//{value: undefined, done: true}
複製代碼
藉助對象C的console語句觀察解構賦值的過程
[a1,b1] = c
// 調用iterator-next:0
// 調用iterator-next:1
// a1: 1 b1: a
複製代碼
以上就是迭代協議相關內容及運用
發現了Symbol.iterator屬性的神奇之處,忍不住又看看了Symbol其餘的數據, 發現又一個叫asyncIterator的屬性
參考iterator, 那就是定義了一個異步可迭代對象了吧 ~_~
用於被for await...of 語句循環使用
(注: for await...of 可用於遍歷同步或異步實現迭代器協議的對象)
同iterator,須要含義Symbol.asyncIterator屬性, 提供返回一個無參函數,返回一個包含next方法的對象
暫時可能沒有想到什麼必須合適的場景,那就無病呻吟一下吧,↓
先驗證下for await...of
var a = [Promise.resove(1),Promise.resolve(2),Promise.resolve(3)]
for(let i of a){
console.log(i)
}
// promise * 3
for await(let i of a) {
console.log(i)
}
// 1,2,3
複製代碼
構造一個異步可迭代對象
var asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return Promise.resolve({ value: this.i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
for await (let num of asyncIterable) {
console.log(num);
}
// 0,1,2
複製代碼
目前還木有實現了asyncIterator內置屬性的對象
注: 非標準屬性,只在FF下有實現,慎用
Iterator 函數返回一個對象,它實現了遺留的迭代協議,而且迭代了一個對象的可枚舉屬性。
var a = {a: 1,1: 2,c:3,b:4};
for (var [name, value] of Iterator(a)) {
console.log(name, value);
}
// 1,2 a,1 c,3 b,4
複製代碼