其他章節請看:
es6 快速入門 系列
迭代器 (Iterator) 和 生成器 (Generator)
試圖解決的問題
let colors = ['red', 'blue', 'green', 'yellow']
for(let i = 0, len = colors.length; i < len; i++){
console.log(colors[i])
}
上面是一段標準的 for 回圈代碼,變過變數 i 來跟蹤 colors 的索引,雖然語法簡單,但如果將多個回圈嵌套則需要跟蹤多個變數,代碼復雜度會大增,一不小心就錯誤的使用了其他 for 回圈的跟蹤變數,導致程式出錯,迭代器的出現旨在消除這種復雜性并減少回圈中的錯誤
解決的方法
使用迭代器優化上述問題,請看代碼:
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 創建一個迭代器:
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 引入生成器,讓創建迭代器的程序變得簡單
什么是生成器
生成器是一種回傳迭代器的函式,通過 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 回圈
首先來回答上面遺留的問題:陣列、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都內建了以下三種迭代器:
- entries() 回傳一種迭代器,其值為多個鍵值對
- values() 回傳一種迭代器,其值為集合的所有值
- keys() 回傳一種迭代器,其值為集合的所有鍵名
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 型別也擁有的默認迭代器,其行為與陣列的默認迭代器完全一致
其他章節請看:
es6 快速入門 系列
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/264731.html
標籤:其他
