ECMAScript 中的迭代器講解

這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰前端

許多初級前端開發者在往中級邁進的過程當中,面試常常問到的一個就是迭代器和生成器,其實在開發中都用過,可是並不知道這是什麼,或者有些許瞭解但並不夠深刻。那這篇文章就對這一部分開發者會有必定的幫助,講清楚迭代器這玩意。web

較早的迭代

迭代確定知道,簡單理解起來就是循環,在JavaScript 中,計數循環即是最簡單的一種。示例:面試

for(let i = 0; i < 9; ++i){
	console.log("[ i ]", i);
}
複製代碼

迭代的基礎就是循環,它包含幾個必要條件:數組

  • 能夠指定迭代的次數
  • 能夠指定每次迭代執行的操做
  • 每次迭代都在下一次迭代開始前完成
  • 順序都是事先定義好的

當須要循環遍歷一個數組的時候,迭代是在一個有序的集合上進行的,「有序」即爲數組中的全部元素均可以按照順序從第一項到最後一項被遍歷到。由於數組有肯定的長度,以及每一項均可以經過索引下標去獲取,也就是說能夠經過索引去遍歷整個數組。示例:markdown

const arr = ["a", "b", "c"];

for(let i = 0; i < arr.length; ++i){
	console.log(arr[i]);
}
複製代碼

可是這種模式必需要事先知道使用的是什麼數據結構,例如數組,若是換成其它數據類型,或者具備隱式順序的數據結構,那麼遍歷的順序就不可肯定。 因而在 ES5 中新增了forEach()方法。示例:數據結構

const arr = ["a", "b", "c"];

arr.forEach(item=>{
	console.log(item);
});
複製代碼

這個方法就不用同數組索引去遍歷和獲取單項的取值,但沒法標識迭代何時結束,所以僅適用於數組的遍歷。爲了解決這些問題,ES6 以後,JavaScript 支持了迭代器模式。函數

迭代器模式

迭代器模式是一種很是抽象的說法,能夠把它理解成數組或者集合這一類的對象,它們的元素是有限的,且互相獨立無歧義。引用紅寶書的解釋,即爲:post

迭代器模式(特別是在ECMAScript這個語境下)描述了一個方案,便可以把有些結構稱爲「可迭代對象」(iterable),由於它們實現了正式的Iterable接口,並且能夠經過迭代器Iterator消費。網站

迭代器工廠函數

迭代器工廠函數,也就是 Symbol.iterator(),它是大部份內置類型都含有的默認屬性,經過它暴露 Iterable 接口(可迭代協議),也就是說要想數據類型支持迭代,那麼該類型必須支持可迭代協議。 ECMAScript 中規定暴露的默認迭代器,必須以「Symbol.iterator」做爲鍵,返回一個新的迭代器。檢查是否存在默認迭代器屬性的方法也很簡單。示例:ui

const obj = {};
const arr = ["a", "b", "c"];

console.log(obj[Symbol.iterator]); // underfined
console.log(arr[Symbol.iterator]); // f values() { [native code] }

console.log(arr[Symbol.iterator]()); // ArrayIterator {}
複製代碼

固然,咱們實際開發中是不用顯示調用迭代器工廠函數的,支持可迭代協議的數據類型會自動兼容接受可迭代對象的任何語言特性,例如當咱們使用循環、for-of、解構、擴展操做符的時候,會自動在後臺調用提供的可迭代對象的迭代器工廠函數,從而建立一個迭代器。

迭代器協議

迭代器協議約定迭代器是一種一次性使用的對象,當調用迭代器工廠函數後,返回一個next()方法,每一次迭代成功都會調用該方法,得知下一個迭代的值,若是不調用,則不肯定迭代的當前位置。 next()方法返回一個對象,包含量屬性:donevalue,done 表示是否能夠繼續調用next()方法獲取下一個值,意爲是否「耗盡」,返回一個 Boolean 值; value 表示可迭代對象的下一個值。done 爲 true 時,value 則爲 underfined。done 爲 false 時,則會繼續調用下一個迭代。示例:

// 可迭代對象
let arr = ['foo', 'bar'];// 迭代器工廠函數
console.log(arr[Symbol.iterator]);// f values() { [native code] }

// 迭代器
let iter = arr[Symbol.iterator]();
console.log(iter); // ArrayIterator{}

// 執行迭代
console.log(iter.next()); // { done: false, value: 'foo' }
console.log(iter.next()); // { done: false, value: 'bar' }
console.log(iter.next()); // { done: true, value: undefined }
複製代碼

寫在最後

經過迭代器協議,你能夠實現一個自定義的迭代器,好比規定迭代器能夠被迭代的次數,或者提早終止迭代。

寫做不易,但願能夠得到你的一個「贊」。若是文章對你有用,能夠選擇「收藏」。 若有文章有錯誤或建議,歡迎評論指正,謝謝你。❤️

歡迎閱讀其它文章

相關文章
相關標籤/搜索