本文旨在分析理解 Iterators 。 Iterators 是 JavaScript 中的新方法,能夠用來循環任意集合。在ES6中登場的Iterators。因其可被普遍使用,而且已在多處場景派上用場,現已十分流行。html
咱們從概念上去理解iterators,經過實例講述在何處使用。而且. We’ll also see some of its implementations in JavaScript.node
若是你有下面的數組 ——es6
const myFavouriteAuthors = [ 'Neal Stephenson', 'Arthur Clarke', 'Isaac Asimov', 'Robert Heinlein' ];
有時,你須要獲取這個數組中每個值,在屏幕上顯示它們,操做它們,或者依據它們作些事情。若是我問你將如何處理?你會說,這很簡單——我循環它們就是了,能夠用for__, while__, for-of 或者 這些 循環方法中的任意一個。web
若是如今不是前面的數組,而是以自定的數據結構保存全部的authors,好比——數組
如今, myFavouriteAuthors
是一個包含了對象 allAuthors
的對象, allAuthors
包含了三個數組,對應key值爲 fiction
, scienceFiction
,和 fantasy
。 如今若是須要遍歷 myFavouriteAuthors
來獲取全部的做者, 你的方法是什麼? 你能夠繼續嘗試一些循環組合來獲取全部數據。瀏覽器
然而,若是你這樣作 —數據結構
for (let author of myFavouriteAuthors) { console.log(author) } // TypeError: {} is not iterable</pre>
你會獲得一個該對象不是_可迭代的_TypeError。 咱們來看看迭代是什麼,以及咱們如何使對象可迭代。 在本文的最後,你將知道如何在這種狀況下,在 myFavouriteAuthors
上,在自定義對象上使用 for-of
循環。ide
在上一節中看到了問題所在。 沒有方法能夠簡單得從咱們的自定義對象中獲取全部做者。 咱們想要一種方法,經過它咱們能夠有序地呈現全部內部數據。函數
讓咱們在 myFavouriteAuthors
中添加一個返回全部做者的方法 getAllAuthors
。 像這樣 ——oop
這是一個簡單的方法。 它完成了得到全部做者的當下目標。 可是,這種實現可能會出現一些問題。 好比——
getAllAuthors
這個名字很是具體。 若是其餘人正在建立他們本身的 myFavouriteAuthors
,他們可能會將其命名爲 retrieveAllAuthors
。getAllAuthors
。getAllAuthors
返回包含全部做者的字符串數組。 若是另外一個開發人員以這種格式返回一個對象數組會怎樣——[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]</pre>
開發人員必須知道,返回全部數據的方法的 確切名稱和返回類型 。
若是咱們制定一個 規則 ,該方法的 名稱 及其 返回類型 , 是固定且不可更改的 ,這怎麼辦?
讓咱們將這個方法命名爲—— iteratorMethod .
ECMA 採起了相似的步驟,來標準化循環自定義對象的過程。可是,ECMA使用 Symbol.iterator
而不是 iteratorMethod
。 Symbols 提供惟一且不能與其餘屬性名稱衝突的名稱。 此外, Symbol.iterator
將返回一個名爲 iterator
的對象。 這個迭代器將有一個名爲 next
的方法,它將返回一個包含key爲 value
和 done
對象,
key value
中將包含當前值。 它能夠是任何類型。 done
是布爾值。 它表示是否已獲取全部值。
下圖可能有助於創建 iterables , iterators 和 next 之間的關係。 這種關係稱爲迭代協議。
![iterables, iterators, 和 next之間的關係。
](http://upload-images.jianshu....
參考 Axel Rauschmayer博士 的 Exploring JS 一書 —
Symbol.iterator
的方法來實現。 該方法是 iterators 的工廠。 也就是說,它將建立 iterators **.正如咱們在上一節中所學到的,咱們須要實現一個名爲 Symbol.iterator
的方法。咱們將使用 computed property syntax 來設置這個key。舉一個簡短的例子 —
在第4行,咱們建立iterator。 這是一個定義了 next
方法的對象。 next
方法根據 step
變量返回對應的值。 在第25行,咱們取到 iterator
。 27行,咱們調用 next
方法。 接下來咱們繼續調用,直到 done
變成'true`。
這正是 for-of
循環中發生的事情。 for-of
循環採用 iterable ,併爲其建立 iterator 。 不斷調用 next()
直到 done
爲真。
不少東西在JavaScript中都是可迭代的。 它可能不是立等可見的,但若是仔細觀察,是能看到iterables的。
arguments
— 函數中一個相似數組的特殊變量for-of
循環 — for-of
循環須要迭代。 不然,它將拋出一個 TypeError
.for (const value of iterable) { ... }</pre>
代碼:
const array = ['a', 'b', 'c', 'd', 'e']; const [first, ,third, ,last] = array;</pre>
至關於
const array = ['a', 'b', 'c', 'd', 'e']; const iterator = array[Symbol.iterator](); const first = iterator.next().value iterator.next().value // Since it was skipped, so it's not assigned const third = iterator.next().value iterator.next().value // Since it was skipped, so it's not assigned const last = iterator.next().value</pre>
代碼:
const array = ['a', 'b', 'c', 'd', 'e']; const newArray = [1, ...array, 2, 3];</pre>
能夠寫成
const array = ['a', 'b', 'c', 'd', 'e']; const iterator = array[Symbol.iterator](); const newArray = [1]; for (let nextValue = iterator.next();nextValue.done !== true;nextValue = iterator.next()) { newArray.push(nextValue.value); } newArray.push(2) newArray.push(3)
Promise.all
和 Promise.race
接受Promises上的迭代。Map的構造函數將 [key,value]
形式的迭代器轉換爲Map,Set的構造函數將可迭代的元素轉換爲Set——
const map = new Map([[1, 'one'], [2, 'two']]); map.get(1) // one const set = new Set(['a', 'b', 'c]); set.has('c'); // true
這是一個使myFavouriteAuthors可迭代的實現方式。
可迭代的實現示例
根據本文的介紹,您能夠輕鬆瞭解迭代器的工做方式。 可能有點難以理解它的邏輯,因此,我已經爲代碼寫了註釋。 可是,吸取和理解概念的最佳方法是讓這些代碼在瀏覽器或node中運行起來。
若有疑問,歡迎回復! 參考: