弄懂!!ES6中的Iterator迭代器

本文雲紋連接🔗javascript

專門說一說Iterator迭代器的緣由是,爲後面async/await的文章作鋪墊,由於我async/await是由Generator+Promise共同構成,而其中的Generator就是依賴於迭代器Iteratorjava

下面讓咱們來看看什麼是Iterator?它出現的目的是什麼?如何使用它?es6

Iterator迭代器

名詞: 迭代 iteration / 可迭代 iterable / 迭代器 iterator

想必你們使用過for循環、while循環等,遍歷Array獲取其中的值,那其餘數據結構如何經過遍歷獲取呢?或者這樣說,是否能夠提供一個統一的訪問機制?來訪問Object、Map、Set等。編程

輪到Iterator迭代器出場,Iterator迭代器就是爲了解決這個問題,它提供統一的接口,爲不一樣的數據結構提供統一的訪問機制。(目前Map、Set、Array支持Iterator)。segmentfault

顧名思義,Iterator迭代器的出現就是爲了迭代而生,爲不一樣的集合:Object、Array、Map、Set,提供了一個統一的接口(這裏接口能夠簡單的理解爲方法,就是遍歷方法)。向咱們經常使用的for...of就是依賴與Iterator迭代器。數組

在這裏順便提一嘴,我理解到的遍歷、迭代的關係:遍歷就是訪問數據結構的全部元素,而迭代是遍歷的一種形式。數據結構

// 阮一峯 ECMAScript 6 入門
// 模擬next方法返回值
var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.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}
    }
  }
}

上面的makeIterator函數,它就是一個迭代器生成函數,做用就是返回一個迭代器對象。對數組執行這個函數,就會返回該數組的迭代器對象it異步

經過調用next函數,返回valuedone兩個屬性;value屬性返回當前位置的成員,done屬性是一個布爾值,表示遍歷是否結束,便是否還有必要再一次調用next方法;當done爲true時,即遍歷完成。async

小結Iterator迭代器就是一個接口方法,它爲不一樣的數據結構提供了一個統一的訪問機制;使得數據結構的成員可以按某種次序排列,並逐個被訪問異步編程

Iterator規範

在上面的代碼中,迭代器對象it包含一個next() 方法,調用next()方法,返回兩個屬性:布爾值done和值value,value的類型無限制。

迭代器對象包含的屬性咱們知道了,那麼在平常開發中,咱們如何讓一個對象成爲一個可迭代對象呢?(可迭代對象即支持迭代器規範的對象

要成爲可迭代對象, 一個對象必須實現@@iterator方法。這意味着對象(或者它原型鏈上的某個對象)必須有一個鍵爲@@iterator的屬性,可經過常量 Symbol.iterator 訪問該屬性。

let myIterable = {
    a: 1,
    b: 2,
    c: 3
}
myIterable[Symbol.iterator] = function() {
  let self = this;
  let arr = Object.keys(self);
  let index = 0;
  return {
    next() {
      return index < arr.length ? {value: self[arr[index++]], done: false} : {value: undefined, done: true};
    }
  }
}

var it = myIterable[Symbol.iterator]();

it.next();

for(const i of myIterable) {
  console.log(i);
}

myIterable對象添加Symbol.iterator屬性,同時在返回的next方法中,添加兩個屬性,既讓它成爲了一個可迭代對象。(其實若是真的有這樣的需求,能夠考慮使用Map)。

小結Iterator規範————Iterator迭代器包含一個next()方法,方法調用返回返回兩個屬性:donevalue;經過定義一個對象的Symbol.iterator屬性,便可將此對象修改成迭代器對象,支持for...of遍歷。

IteratorGenerator

GeneratorPromise同樣,都是提供異步編程解決方案。其實Generator函數就是一個普通函數,可是有兩個特徵,一是,function關鍵字與函數名之間有一個星號*;二是,函數內部使用yield表達式,定義不一樣的內部狀態。來看看Generator函數的使用:

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }

經過上面的例子能夠知道,Generator函數執行後,會返回一個Iterator對象。在Generator中的yield表達式,yield會記住當前代碼運行的狀態和位置,等在調用這串代碼的時候會依次日後走。

Iterator(迭代器)就是一個可迭代的對象,而Generator(生成器)使用了yield或者生成器表達式,生成iterator對象,用一種方便的方法實現了iterator,在for循環取數據或使用next()取數據.

小結Generator(生成器)能夠理解爲是對Iterator(迭代器)的一種實現。

Iterator應用

Generator(生成器)就是其中最典型的一個應用,固然還有其餘,例如:Map、Set、Array等原生具有Iterator(迭代器),支持for...of循環。

Obejct實現Iterator接口

Object對象雖然不支持Iterator(迭代器),但咱們可使用Generator(生成器)進行包裝。

let obj = {a: 1, b: 2, c: 3}
function* entries(obj) {
  for (let key of Object.keys(obj)) {
    yield [key, obj[key]];
  }
}
for (let [key, value] of entries(obj)) {
  console.log(key, '->', value);
}

目前在Array、Map、Set、String、TypedArray、函數的 arguments 對象、NodeList 對象,原生具有Iterator接口。

參考:

阮一峯:Iterator 和 for...of 循環

MDN 迭代協議

白話解釋 迭代器(ITERATOR)和生成器(GENERATOR)

Python/Iterator and Generator 關係

相關文章
相關標籤/搜索