做者:Brandon Morellihtml
譯者:前端小智前端
來源:Mediumgit
阿里雲最近在作活動,低至2折,有興趣能夠看看:promotion.aliyun.com/ntms/yunpar…es6
爲了保證的可讀性,本文采用意譯而非直譯。github
本文旨在分析理解 Iterators。 Iterators 是 JS中的新方法,能夠用來循環任意集合。 在ES6中登場的Iterators。因其可被普遍使用,而且已在多處場景派上用場, 咱們將從概念上理解迭代器是什麼,以及在何處使用它們和示例。咱們還將看到它在JS 中的一些實現。數組
假設有這樣數組數據結構
const myFavouriteAuthors = [
'Neal Stephenson',
'Arthur Clarke',
'Isaac Asimov',
'Robert Heinlein'
];
複製代碼
在某些狀況下,但願返回數組中的全部單獨值,以便在屏幕上打印它們、操做它們或對它們執行某些操做。函數
如何處理? 簡單方法就是使用 for
, while
, for-of
方法。工具
以下:學習
如今,假設你擁有一個自定義數據結構來保存全部authors
myFavouriteAuthors
是一個對象,它包含另外一個對象 allAuthors
。allAuthors
包含三個數組,其中包含 fiction
、scienceFiction
和 fantasy
。
如今,若是要求你循環遍歷 myFavouriteAuthors
以得到全部的author
,你的方法是什麼? 你可能會嘗試一些循環組合來得到全部數據。
可是,若是你這樣作了 ——
for (let author of myFavouriteAuthors) {
console.log(author)
}
// TypeError: {} is not iterable
複製代碼
你將獲得一個類型錯誤,說明該對象不可迭代。讓咱們看看什麼是可迭代的,以及如何使對象可迭代。
在上一節中看到了問題,從咱們的自定義對象中獲取全部的author
是不容易的。咱們須要某種方法,經過它咱們能夠有序地獲取內部數據。
咱們在 myFavouriteAuthors
中添加一個返回全部做者的方法 getAllAuthors
。如:
這是一個簡單的方法。它幫咱們完成了獲取全部author
的功能。可是,這種實現可能會出現一些問題:
getAllAuthors
的名稱很是具體。若是其餘人正在建立本身的 myFavouriteAuthors
,他們可能會將其命名爲retrieveAllAuthors
。
做爲開發人員,咱們老是須要知道返回全部數據的特定方法,在本例中,它被命名爲getAllAuthors
。
getAllAuthors
返回的是字符串數組,若是另外一個開發人員以這種格式返回一個對象數組,該怎麼辦:
[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]
開發人員必須知道返回全部數據的方法的確切名稱和返回類型。
若是咱們規定方法的名稱和它的返回類型是固定不變的呢?
讓咱們將這個方法命名爲 --- iteratorMethod
ECMA 也採起了相似的步驟來標準化在定製對象上循環的過程。可是,ECMA 沒有使用名稱 iteratorMethod
,而是使用名稱 Symbol.iterator。
Symbols 提供的名稱是惟一的,不能與其餘屬性名稱衝突。同時,Symbol.iterator 返回一個名爲迭代器的對象,這個迭代器將擁有一個名爲next
的方法,該方法將返回一個具備鍵值爲 value
和 done
的對象。
值鍵 value
包含當前值,它能夠是任何類型的,done
是布爾值,它表示是否獲取了全部的值。
下圖能夠幫助創建可迭代對象、迭代器和next
之間的關係,這種關係稱爲迭代協議。
根據Axel Rauschmayer博士的《探索JS》一書:
可迭代是一種數據結構,它但願使其元素對外部可訪問,經過實現一個關鍵字是Symbol.iterator
的方法來實現,該方法是迭代器的工廠,也就是說,它將建立迭代器。
迭代器是一個指針,用於遍歷數據結構的元素,咱們將使用computed property語法來設置這個鍵,以下:
所以,正如咱們在上一節學到的,咱們須要實現一個名爲Symbol.iterator
的方法
在第4行,咱們建立迭代器。它是一個定義了next
方法的對象。next
方法根據step
變量返回值。在第25行,咱們檢索iterator
,27 行,咱們調用next
方法,直到 done
的值爲 true。
這正是for-of
循環中發生的事情,for-of
接受一個迭代器,並建立它的迭代器,它會一直調用next(),直到 done
爲 true。
JS 中的不少對象都是可迭代的。它們可能不是很好的察覺,可是若是仔細檢查,就會發現迭代的特徵:
arguments
—— 函數中相似數組的特殊變量JS中使用迭代的其餘一些結構是:
for-of
-- for-of 循環須要一個可迭代的對象,不然,它將拋出一個類型錯誤。
for (const value of iterable) { ... }
數組解構 -- 因爲可迭代性,會發生析構。讓咱們來看看:
const array = ['a', 'b', 'c', 'd', 'e']; const [first, ,third, ,last] = array;
等價於:
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
複製代碼
擴展操做符(…)
const array = ['a', 'b', 'c', 'd', 'e'];
const newArray = [1, ...array, 2, 3];
等價於:
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
接受可迭代對象
Maps 和 Sets
下面是一個實現,它使myFavouriteAuthors
具備可迭代性:
const myFavouriteAuthors = {
allAuthors: {
fiction: [
'Agatha Christie',
'J. K. Rowling',
'Dr. Seuss'
],
scienceFiction: [
'Neal Stephenson',
'Arthur Clarke',
'Isaac Asimov',
'Robert Heinlein'
],
fantasy: [
'J. R. R. Tolkien',
'J. K. Rowling',
'Terry Pratchett'
],
},
[Symbol.iterator]() {
// 獲取數組中的全部做者
const genres = Object.values(this.allAuthors);
// 存儲當前類型和索引
let currentAuthorIndex = 0;
let currentGenreIndex = 0;
return {
// Implementation of next()
next() {
// 根據當前的索引獲取對應的做者信息
const authors = genres[currentGenreIndex];
// 當遍歷完數組 authors是,oNotHaveMoreAuthors 爲 true
const doNothaveMoreAuthors = !(currentAuthorIndex < authors.length);
if (doNothaveMoreAuthors) {
// 加一繼續訪問下一個
currentGenreIndex++;
// 重置
currentAuthorIndex = 0;
}
// 若是全部 genres 都遍歷完告終,那麼咱們須要告訴迭代器不能提供更多的值。
const doNotHaveMoreGenres = !(currentGenreIndex < genres.length);
if (doNotHaveMoreGenres) {
return {
value: undefined,
done: true
};
}
// 若是一切正常,從當genre 返回 做者和當前做者索引,以便下次,下一個做者能夠返回。
return {
value: genres[currentGenreIndex][currentAuthorIndex++],
done: false
}
}
};
}
};
for (const author of myFavouriteAuthors) {
console.log(author);
}
console.log(...myFavouriteAuthors)
複製代碼
經過本文得到的知識,你能夠很容易地理解迭代器是如何工做的,這種邏輯可能有點難以理解。所以,理解這個概念的最佳方法是多多敲死代碼,多多驗證!
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
阿里雲最近在作活動,低至2折,有興趣能夠看看:promotion.aliyun.com/ntms/yunpar…
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。