深入理解ES6之迭代器與生成器

迭代器

迭代器是被設計專用于迭代的對象,帶有特定接口。所有的迭代器對象都擁有next()方法,會返回一個結(jié)果對象。該結(jié)果對象有兩個屬性:對應下一個值的value,以及一個布爾類型的done,其值為true時表示沒有更多值可供使用。迭代器持有一個指向集合位置的內(nèi)部指針,每當調(diào)用了next()方法,迭代器就會返回相應的下一個值。

使用es5模擬一個迭代器

function createIterator(items) {
  var i = 0
  // 返回一個迭代器對象
  return {
    next: () => {
      var done = i >= items.length
      var value = !done ? items[++i] : undefined
      return {
        done,
        value
      }
    }
  }
}

var list = createIterator([1, 2, 3, 4, 5])
console.log(list.next())    // { done: false, value: 2 }
console.log(list.next())    // { done: false, value: 3 }
console.log(list.next())    // { done: false, value: 4 }
console.log(list.next())    // { done: false, value: 5 }
console.log(list.next())    // { done: true, value: undefined }

生成器

生成器(generator)是能返回一個迭代器的函數(shù)。生成器函數(shù)由放在function關(guān)鍵字之后的一個星號(*)來表示,并能使用新的yield關(guān)鍵字。將星號緊跟在function關(guān)鍵字之后,或是在中間留出空格,都是沒問題的。

function *createIterator() {
  yield 1
  yield 2
  yield 3
}

let iterator = createIterator()

console.log(iterator.next().value)    // 1
console.log(iterator.next().value)    // 2
console.log(iterator.next().value)    // 3

可迭代對象與 for-of 循環(huán)

與迭代器緊密相關(guān)的是,可迭代對象(iterable)是包含Symbol.iterator屬性的對象。這個Symbol.iterator知名符號定義了為指定對象返回迭代器的函數(shù)。在 ES6 中,所有的集合對象(數(shù)組、 Set 與 Map )以及字符串都是可迭代對象,因此它們都被指定了默認的迭代器。

for-of循環(huán)在循環(huán)每次執(zhí)行時會調(diào)用可迭代對象的next()方法,并將結(jié)果對象的value值存儲在一個變量上。循環(huán)過程會持續(xù)到結(jié)果對象的done屬性變成true為止。

let value = [1, 2, 3]
for (let num of value) {
  console.log(num)
}

輸出:

1
2
3

訪問默認迭代器 Symbol.iterator

let values = [1, 2, 3, 4, 5]
let iterator = values[Symbol.iterator]()
iterator.next()    // {value: 1, done: false}
iterator.next()    // {value: 2, done: false}
iterator.next()    // {value: 3, done: false}

集合的迭代器

ES6 具有三種集合對象類型:數(shù)組、 Map 與 Set 。

  • entries():返回一個包含鍵值對的迭代器;
  • values():返回一個包含集合中的值的迭代器;
  • keys():返回一個包含集合中的鍵的迭代器。
let map = new Map([['name', 'age'], ['map', 5]])
map.entries()    // MapIterator {"name" => "age", "iterator" => 5, "friends" => "none"}
map.values()    // MapIterator {"map", 5}
map.keys()    // MapIterator {"name", "age"}

let set = new Set([1, 2, 3, 4, 5])
set.entries()    // SetIterator {1 => 1, 2 => 2, 3 => 3}
set.values()    // SetIterator {1, 2, 3, 4, 5}
set.keys()    // SetIterator {1, 2, 3, 4, 5}

let arr = [1, 2, 3, 4, 5]
arr.entries()    // Array Iterator {}
arr.values()    // Array Iterator {}
arr.keys()    // Array Iterator {}

調(diào)用迭代器方法返回的數(shù)據(jù)需要通過 for...of... 來遍歷

字符串的迭代器

從 ES5 發(fā)布開始, JS 的字符串就慢慢變得越來越像數(shù)組。例如 ES5 標準化了字符串的方括號表示法,用于訪問其中的字符(即:使用text[0]來獲取第一個字符,以此類推)。

所以也可以像遍歷集合那樣遍歷字符串

  • 傳統(tǒng) for 循環(huán)
  • for...of...

NodeList 的迭代器

文檔對象模型( DOM )具有一種NodeList類型,用于表示頁面文檔中元素的集合。NodeList對象與數(shù)組都使用了length屬性來標明項的數(shù)量,并且都使用方括號表示法來訪問各個項。然而本質(zhì)上來說,NodeList與數(shù)組的行為是完全不同的,這會引發(fā)許多混亂。
著默認迭代器被附加到 ES6 , DOM 關(guān)于NodeList的規(guī)定也包含了一個默認迭代器(此規(guī)定在 HTML 規(guī)范而非 ES6 規(guī)范中),其表現(xiàn)方式與數(shù)組的默認迭代器一致。這意味著你可以將NodeList用于for-of循環(huán),或用于其他使用對象默認迭代器的場合。

let divs = document.getElementsByTagName("div")
for (let div of divs) {
  console.log(div.id)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容