其餘章節請看:javascript
es6 快速入門 系列html
let colors = ['red', 'blue', 'green', 'yellow'] for(let i = 0, len = colors.length; i < len; i++){ console.log(colors[i]) }
上面是一段標準的 for 循環代碼,變過變量 i 來跟蹤 colors 的索引,雖然語法簡單,但若是將多個循環嵌套則須要跟蹤多個變量,代碼複雜度會大增,一不當心就錯誤的使用了其餘 for 循環的跟蹤變量,致使程序出錯。迭代器的出現旨在消除這種複雜性並減小循環中的錯誤java
使用迭代器優化上述問題,請看代碼:es6
let colors = ['red', 'blue', 'green', 'yellow'] for(let color of colors){ console.log(color) // 依次輸出:red blue green yellow }
每一個集合(數組、Map和Set)類型都有一個默認的迭代器,在 for-of 循環中,若是沒有顯示指定則使用默認迭代器數組
關於迭代器是什麼,生成器是什麼,這裏的數組、for-of和迭代器三者之間的關係又是什麼,函數
全部這些疑問都能在下面的補充章節中找到解答優化
下面咱們用 es5 建立一個迭代器:es5
function createIterator(items){ let i = 0; let len = items.length; return { next: function(){ const result = { value: items[i], done: i++ >= len } return result; } } } let iterator = createIterator(['a', 'b', 'c']) console.log(iterator.next()) // { value: 'a', done: false } console.log(iterator.next()) // { value: 'b', done: false } console.log(iterator.next()) // { value: 'c', done: true } console.log(iterator.next()) // { value: undefined, done: true }
迭代器是一個特殊的對象,它有專門爲迭代過程而設計的專有接口,全部的迭代器都有 next() 方法,每次調用 next() 都返回一個結果對象。結果對象有兩個屬性:一個是value,表示下一個將要返回的值;另外一個是done,是一個布爾值類型的值,當沒有更多返回數據時返回true設計
上面這個示例很複雜,es6 中迭代器的編寫規則也很複雜,因此 es6 引入生成器,讓建立迭代器的過程變得簡單code
生成器是一種返回迭代器的函數。經過 function 關鍵字後面的星號(*)來表示,函數中會用到新的關鍵字 yield。
下面咱們用生成器重寫上面的 createIterator() 方法:
// 星號* 能夠緊挨着 function 關鍵字,也能夠在中間加空格 function *createIterator(items){ for(let i = 0, len = items.length; i < len; i++){ yield items[i] } } let iterator = createIterator(['a', 'b', 'c']) console.log(iterator.next()) // { value: 'a', done: false } console.log(iterator.next()) // { value: 'b', done: false } console.log(iterator.next()) // { value: 'c', done: false } console.log(iterator.next()) // { value: undefined, done: true }
createIterator()前面的星號代表它是一個生成器;yield 是 es6 中的新特性,能夠經過它來指定調用迭代器的 next() 方法時的返回值和返回順序。
生成器最有趣的大概是,每次執行完 yield 語句後,函數會自動中止執行。
yield只能在生成器內部使用。下面例子中,從字面上看,yield 確實是在生成器內部,可是它與 return 同樣,兩者都不能穿透函數邊界。
function *createIterator(items){ items.forEach(function(){ yield 1 // 報錯 }) }
注:不能用箭頭函數建立生成器
首先來回答上面遺留的問題:數組、for-of 和迭代器三者之間的關係是什麼?
let colors = ['red', 'blue', 'green', 'yellow'] for(let color of colors){ console.log(color) // 依次輸出:red blue green yellow }
es6中,全部的集合(數組、Map及Set)和字符串都是可迭代對象。一個對象若是有與之對應的迭代器,那麼它就是可迭代對象;for-of 循環每執行一次都會調用可迭代對象的 next() 方法,並將迭代器返回的結果對象中的 value 存儲在一個變量中,循環將持續到返回對象的 done 屬性的值爲 true。
三者之間的關係這就很清楚了,數組有本身的迭代器,for-of 會循環迭代器
es6中的可迭代對象具備 Symbol.iterator 屬性,執行 Symbol.iterator 指定的函數會返回一個做用於該對象的迭代器,以數組爲例:
let arr = [11, 22] let iterator = arr[Symbol.iterator]() console.log(iterator.next()) // { value: 11, done: false } console.log(iterator.next()) // { value: 22, done: false } console.log(iterator.next()) // { value: undefined, done: true }
注:若是將 for-of 語句用於不可迭代對象、null 或 undefined 將會致使程序報錯
爲了更好的訪問數據,es6給數組、Set和Map都內建瞭如下三種迭代器:
let arr = [11, 22] for(let entry of arr.entries()){ // 依次輸出:[ 0, 11 ] [ 1, 22 ] console.log(entry) } for(let key of arr.keys()){ // 依次輸出:0 1 console.log(key) }
每種集合都有一個默認的迭代器,在 for-of 循環中,若是沒有顯示指定則使用默認的迭代器。數組和 Set 的默認迭代器是 values() 方法,Map 的默認迭代器是 entries() 方法
let arr = [11, 22] for(let value of arr.values()){ // 依次輸出:11 22 console.log(value) } // 等同於 let arr = [11, 22] for(let value of arr){ // 依次輸出:11 22 console.log(value) }
自從 es6 添加了迭代器,DOM 中的 NodeList 類型也擁有的默認迭代器,其行爲與數組的默認迭代器徹底一致
其餘章節請看: