這真是毅種循環數組
Iterator不是array,也不是set,不是map, 它不是一個實體,而是一種訪問機制
,是一個用來訪問某個對象的接口規範,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署Iterator接口,就能夠完成遍歷操做
(即依次處理該數據結構的成員)。數據結構
Iterator的遍歷某個數據結構過程是這樣的(好比對array進行遍歷)函數
建立一個指針對象,指向當前數組的起始位置
。也就是說,遍歷器對象本質上,就是一個指針對象this
第一次調用指針對象的next方法
,能夠將指針指向數據結構的第一個成員, 這時候的返回值是{value:array[0], done:false}指針
第二次調用指針對象的next方法
,指針就指向數據結構的第二個成員,這時候的返回值是{value:array[1], done:false}code
不斷調用指針對象的next方法
,直到它指向數據結構的結束位置這時候的返回值是{value:array[array.length-1], done:true}對象
遍歷完畢接口
爲數組['a','b']手動寫一個iterator接口內存
var itertaor = makeIterator(['a', 'b']); iterator.next() // { value: "a", done: false } iterator.next() // { value: "b", done: false } iterator.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
等價於:部署
let iterator = makeIterator(['a','b'])= {next:function(){xxxx}}
等價於:
iterator.next() = nextIndex<array.length ?{value: array[nextIndex++], done: false} :{value: undefined, done: true};
因此當 var iterator = makeIterator(['a','b'])
執行完,這時候makeIterator函數內部的nextIndex=0
, 但因爲makeIterator
給外部變量iterator
返回了一個引用{next:function(){xxx}}
,因此makeIterator函數沒法關閉,如今處於內存泄漏狀態(函數的執行上下文環境沒有關閉啊我摔!),
執行完第一個iterator.next()的時候, 因爲此時nextIndex=0, nextIndex<array.length成立,返回的是{value: array[nextIndex++], done: false}
,這一句實際等價於: 返回{value: array[nextIndex], done: false}
而後nextIndex=nextIndex+1
,如今nextIndex=1了
執行完第二個iterator.next()的時候, 因爲此時nextIndex=1, nextIndex<array.length成立,返回的是{value: array[nextIndex++], done: false}
,這一句實際等價於: 返回{value: array[nextIndex], done: false}
而後nextIndex=nextIndex+1
,如今nextIndex=2了
執行完第三個iterator.next()的時候, 因爲此時nextIndex=2, nextIndex<array.length不成立,返回的是{value: undefined, done: true}
事實上,咱們不須要手動寫array/set/map
的Iterator接口了,由於ES6規定它們是可遍歷對象
,因此對應的Iterator接口已經被添加到對應的Symbol.iterator
屬性上了(因此這三種數據結構才能用keys(for..of)/values(for..of)/entries(for..of)/foreach
這種方法進行遍歷),你能夠經過以下方式來獲取
let arr = ['a', 'b', 'c']; let arrIterator = `arr[Symbol.iterator]()` let set = new Set([1,2,3]); let setIterator = `set[Symbol.iterator]()` let map = new Map([x,1][y,2]); let mapIterator = `map[Symbol.iterator]()`
對於非可遍歷對象,好比{a:1,b:2},ES6並無規定這種對象鍵值對爲可遍歷對象,因此用for..of是不能對它進行遍歷的.若是要使一個對象變成可遍歷的,須要手動添加Iterator規則接口到它的Symbol.iterator
屬性上去,好比
let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } };
對於其餘的不可遍歷對象(好比類數組對象),你能夠手動在Symbol.iterator
屬性上部署上手寫的Iterator接口(這樣你本身能夠寫遍歷規則),也可讓Symbol.iterator
屬性直接指向array的Iterator接口(這樣就是用的數組的遍歷規則)