提及迭代器, 那就要先了解迭代模式前端
迭代模式: 提供一種方法能夠順序得到聚合對象中的各個元素, 是一種最簡單,後端
也是最多見的設計模式,它可讓用戶經過特定的接口尋訪集合中的每個元素設計模式
而不用瞭解底層的實現。數組
迭代器 : 依照迭代模式的思想而實現,數據結構
分爲內部迭代器和外部迭代器,函數
內部迭代器: 自己是函數, 該函數內部定義好迭代規則,徹底接手整個迭代過程this
外部只須要一次初始調用,如Array.prototype.forEach, Jquery.eachspa
外部迭代器: 自己是函數, 執行返回迭代對象,迭代下一個元素必須顯示調用,prototype
調用複雜度增長,但靈活性加強。設計
咱們主要來了解一下外部迭代器:
外部迭代器自己是一個函數, 執行這個函數就至關於啓動了這個迭代器,
而後咱們每次迭代須要手動調用next()方法,返回一個對象,
基於此咱們來本身實現一個外部迭代器
const arr = [2,3,4]; function OuterIterator(o) { let curIndex = 0; let next = () => { return { value: o[curIndex], done: o.length === ++curIndex, } }; return { next } } const oIt = OuterIterator(arr); console.log(oIt.next()); console.log(oIt.next()); console.log(oIt.next());
結果:
咱們爲何要用外部迭代器呢 ?
想象一個場景, 後端給前端返回一個數組形式的數據, 前端經過for 循環遍歷
當業務變更時, 後端傳給前端的再也不是數組了, 而是一個對象又
或者是一個Map/Set 結構的數據, 那前端的遍歷代碼就須要大規模重寫。
因此咱們要標準化迭代操做,
解決方案: ES6 引入Iterator, 部署在NodeLlist, argument, Array, Set, Map , 字符串
等數據上的Symbol.iterator屬性 , 使得這些數據是可迭代的, 並可進行
for...of , ... , Array.from等操做。
這裏插播一個內容Symbol: js 第七種 基本數據結構
特色: 惟一, 可做爲對象屬性, 有靜態方法Symbol.iterator
Symbol若是傳入的是對象的話,會隱式調用對象的toString() 方法,好比:
let os = Symbol({'name': 'liu'}); console.log(os); let os2 = Symbol({'name': 'liu', toString() { return "我最帥" }}); console.log(os2);
咱們重寫了對象的toString方法, 結果:
回到主題, 原生有iterator接口的只有NodeLlist, argument, Array, Set, Map , 字符串等數據
對象上是沒有iterator的, 因此它不能被迭代, 也不能進行for...of , ... , Array.from等操做
那咱們要迭代對象怎麼辦呢 ?
沒錯, 就是給它加上咱們本身按照ES6規範寫外部迭代器:
const obj = {
0: 'liu',
1: '18',
2: 'man',
}; console.log([...obj]);
直接用...操做符報錯, obj 不可迭代
const obj = { 0: 'liu', 1: '18', 2: 'man', length: 4, [Symbol.iterator] : function () { let curIndex = 0; let next = () => { return { value: this[curIndex], done: this.length === ++curIndex, } }; return { next } } }; console.log([...obj]);
結果:
obj必須是類數組, 就是屬性是數字 , 且有length屬性 才能這樣寫。
咱們下一篇來討論generator生成器, 它能夠生成一個迭代對象。