1. 程式人生 > >ES6 中的 iterator

ES6 中的 iterator

擴展運算 key pro banner prot ray return 必須 first

【簡介】

遍歷器/叠代器。任何數據結構只要部署 Iterator 接口,就可以完成遍歷操作。這種數據結構是“可遍歷的”(iterable)。

如何判斷是否可遍歷?

 typeof target[Symbol.iterator] // function

【作用】

  1. 為各種數據結構,提供一個統一的、簡便的訪問接口;

  2. 使得數據結構的成員能夠按某種次序排列;

  3. ES6 創造了一種新的遍歷命令for...of 循環,Iterator 接口主要供for...of消費。

【遍歷】

const colors = ["red", "green", "blue"]
for (var i = 0, len = colors.length; i < len; i++) { console.log(colors[i]) }
  1. 追蹤下標位置,
  2. 判斷循環何時停止。

自定義 iterator

function createIterator(items) {
  var i = 0
  return {
    next: function () {
      var done = (i >= items.length)
      var value = !done ? items[i++] : undefined
      
return { done: done, value: value, } } } } var iterator = createIterator([1, 2, 3]) console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next())

Iterator 的遍歷過程:

1、創建一個指針對象,指向當前數據結構的起始位置。也就是說,遍歷器對象本質上,就是一個指針對象。

2、第一次調用指針對象的next方法,可以將指針指向數據結構的第一個成員。

3、不斷調用指針對象的next方法,直到它指向數據結構的結束位置。

雖然是比 for 循環簡單了些,但手動寫個 iterator 太麻煩了,所以ES6 推出 generator ,方便創建 iterator。也就是說,generator 就是一個返回值為 iterator 的函數。

【generator 和 iterator】

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

let iterator = createIterator()
console.log(iterator.next().value)
console.log(iterator.next().value)
console.log(iterator.next().value)

Generator:ES6 提供的一種異步編程解決方案。

執行 Generator 函數會返回一個 iterator 對象,通過這個對象可以依次遍歷 Generator 函數內部的每一個狀態。

【for…of 和 iterator】

const colors = ["red", "green", "blue"];
for (let color of colors) {
  console.log(color);
}

當使用for…of循環遍歷某種數據結構時,該循環會自動去尋找 Iterator 接口,並調用Symbol.iterator方法,返回該對象的默認遍歷器。

for…of循環可以使用的範圍包括數組、Set 和 Map、類似數組對象(arguments、DOM NodeList、 Generator、字符串)。

【內置的 iterator】

ES6 的有些數據結構原生具備 Iterator 接口(比如數組),即不用任何處理,就可以被 for…of 循環遍歷。

原因在於,這些數據結構原生部署了Symbol.iterator屬性,另外一些數據結構沒有(比如對象)。

凡是部署了Symbol.iterator屬性的數據結構,就稱為部署了遍歷器接口。調用這個接口,就會返回一個遍歷器對象。

原生具備 Iterator 接口的數據結構如下。

Array、Map、Set、String、arguments 、NodeList

// Array iterator
const heros = [‘Tony‘, ‘Steve‘, ‘Natasha‘, ‘Banner‘, ‘Thor‘]
for (const hero of heros) {
  console.log(hero)
}

// Map iterator
const sex = ‘male‘
const userMap = new Map([
  [‘name‘, ‘Stark‘],
  [48, ‘age‘ ],
  [‘gender‘, sex]
])

for (let entry of userMap.entries()) {
  console.log(entry)
}

for (let key of userMap.keys()) {
  console.log(key)
}

for (let value of userMap.values()) {
  console.log(value)
}

const numberSet = new Set([1, 2, 2, 3, 4, 4, 5])
for (let entry of numberSet.entries()) {
  console.log(entry)
}

for (let key of numberSet.keys()) {
  console.log(key)
}

for (let value of numberSet.values()) {
  console.log(value)
}

// String iterator
const str = ‘ca ?? r‘for (const c of str) {
  console.log(c)
}

// arguments iterator
function getUserInfo (name, male, age, hobby) {
  console.log(arguments.length)
  for (const arg of arguments) {
    console.log(arg)
  }
}
getUserInfo(‘code monkey‘, ‘male‘, ‘28‘, ‘make money‘)

一個類數組對象如果要具備可被 for...of 循環調用的 Iterator 接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法。

// Array alike iterator
const arrAlike = {
  0: ‘a‘,
  1: ‘b‘,
  2: ‘c‘,
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for (const item of arrAlike) {
  console.log(item) // a b c
}

// 普通對象部署數組的Symbol.iterator方法,並無效果。
const obj = {
  a: ‘a‘,
  b: ‘b‘,
  c: ‘c‘,
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
}

for (const item of obj) {
  console.log(item) // undefined undefined undefined
}

註:普通對象部署數組的Symbol.iterator方法,並無效果。因為數組,Map和類數組對象等結構中的成員都是有順序的,

即都是線性的結構,而對象各成員並沒有一個確定的順序,所以遍歷時先遍歷誰後遍歷誰並不確定。

【解構、擴展運算 和 Iterator】

對數組和 Set 結構進行解構賦值時,會默認調用Symbol.iterator方法。

擴展運算符(...)也會調用默認的 Iterator 接口。

const set = new Set().add(‘a‘).add(‘b‘).add(‘c‘)
const [x, y] = set
console.log(x, y)

const [first, ...rest] = set
console.log(first, rest)

const str = ‘hello‘
console.log([...str])

const arr = [‘b‘, ‘c‘];
console.log([‘a‘, ...arr, ‘d‘])

【小結】

1. Iterator 就是為了提供一種統一的接口機制。任何的數據結構,只要部署了Iterator接口,便可以使用 for…of 來遍歷。

2. es6中有三類結構生來就具有Iterator接口:數組、類數組對象、Map和Set結構。

3. String、類數組對象、函數的arguments對象和nodeList 對象的遍歷以及generator的使用、擴展運算符和解構賦值的操作也會調用到 iterator。

4. 對象不具備 iterator 接口,但是可以通過部署 Symbol.iterator 屬性來使對象可遍歷。

技術分享圖片

ES6 中的 iterator