摘要:文章內容分兩部分前半部分為迭代器模式概念后半部分為中迭代器上半部分開始迭代器模式提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示。下半部分開始的迭代器迭代器等同于遍歷器。執行該函數,會返回一個遍歷器對象。
文章內容分兩部分:
前半部分為 “迭代器模式” 概念;
后半部分為 ES6 中 Iterator (迭代器)
上半部分開始...
迭代器模式:提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示。
簡單理解(白話理解):統一 “集合” 型數據結構的遍歷接口,實現可循環遍歷獲取集合中各數據項(不關心數據項中的數據結構)。
生活小栗子:清單 TodoList。每日清單有學習類、生活類、工作類、運動類等項目,清單列表只管羅列,不管類別。
模式特點為遍歷不同數據結構的 “集合” 提供統一的接口;
能遍歷訪問 “集合” 數據中的項,不關心項的數據結構
模式實現// 統一遍歷接口實現 var each = function(arr, callBack) { for (let i = 0, len = arr.length; i < len; i++) { // 將值,索引返回給回調函數callBack處理 if (callBack(i, arr[i]) === false) { break; // 中止迭代器,跳出循環 } } } // 外部調用 each([1, 2, 3, 4, 5], function(index, value) { if (value > 3) { return false; // 返回false中止each } console.log([index, value]); }) // 輸出:[0, 1] [1, 2] [2, 3]
“迭代器模式的核心,就是實現統一遍歷接口。”
模式細分內部迭代器 (jQuery 的 $.each / for...of)
外部迭代器 (ES6 的 yield)
內部迭代器內部迭代器: 內部定義迭代規則,控制整個迭代過程,外部只需一次初始調用
// jQuery 的 $.each(跟上文each函數實現原理類似) $.each(["Angular", "React", "Vue"], function(index, value) { console.log([index, value]); }); // 輸出:[0, Angular] [1, React] [2, Vue]
優點:調用方式簡單,外部僅需一次調用
缺點:迭代規則預先設置,欠缺靈活性。無法實現復雜遍歷需求(如: 同時迭代比對兩個數組)
外部迭代器: 外部顯示(手動)地控制迭代下一個數據項
借助 ES6 新增的 Generator 函數中的 yield* 表達式來實現外部迭代器。
// ES6 的 yield 實現外部迭代器 function* generatorEach(arr) { for (let [index, value] of arr.entries()) { yield console.log([index, value]); } } let each = generatorEach(["Angular", "React", "Vue"]); each.next(); each.next(); each.next(); // 輸出:[0, "Angular"] [1, "React"] [2, "Vue"]
優點:靈活性更佳,適用面廣,能應對更加復雜的迭代需求
缺點:需顯示調用迭代進行(手動控制迭代過程),外部調用方式較復雜
不同數據結構類型的 “數據集合”,需要對外提供統一的遍歷接口,而又不暴露或修改內部結構時,可應用迭代器模式實現。
下半部分開始...
ES6 的 Iterator 迭代器“迭代器等同于遍歷器。在某些文章中,可能會出現遍歷器的字眼,其實兩者的意思一致。”
JavaScript 中 原有表示 “集合” 的數據結構主要是 “數組(Array)” 和 “對象(Object)”,ES6又新增了 Map 和 Set,共四種數據集合,瀏覽器端還有 NodeList 類數組結構。為 “集合” 型數據尋求統一的遍歷接口,正是 ES6 的 Iterator 誕生的背景。
ES6 中迭代器 Iterator 作為一個接口,作用就是為各種不同數據結構提供統一的訪問機制。任何數據結構只要部署了 Iterator 接口,就可以完成遍歷操作。
Iterator 作用:
為各種數據結構,提供一個統一的、簡便的訪問接口;
使得數據結構的成員能夠按某種次序排列;
為新的遍歷語法 for...of 實現循環遍歷
Iterator只是一種接口,與遍歷的數據結構是分開的。 重溫迭代器模式特點:我只要統一遍歷數據項的接口,不關心其數據結構。
ES6 默認的 Iterator 接口部署在數據結構的 Symbol.iterator 屬性上,該屬性本身是一個函數,代表當前數據結構默認的遍歷器生成函數。執行該函數 [Symbol.iterator](),會返回一個遍歷器對象。只要數據結構擁有 Symbol.iterator 屬性,那么它就是 “可遍歷的” 。
遍歷器對象的特征:
擁有 next 屬性方法;
執行 next(),會返回一個包含 value 和 done 屬性的對象
value: 當前數據結構成員的值
done: 布爾值,表示遍歷是否結束
原生具備 Iterator 接口的數據結構:
Array
Map
Set
String
TypedArray
函數的 arguments 對象
NodeList 對象
let arr = ["a", "b", "c"]; let iterator = arr[Symbol.iterator](); iterator.next(); // { value: "a", done: false } iterator.next(); // { value: "b", done: false } iterator.next(); // { value: "c", done: false } iterator.next(); // { value: undefined, done: false }
原生部署 Iterator 接口的數據結構,無需手動執行遍歷器生成函數,可使用 for...of 自動循環遍歷。
for...of 運行原理:
首先調用遍歷對象 [Symobo.iterator]() 方法,拿到遍歷器對象;
每次循環,調用遍歷器對象 next() 方法,得到 {value: ..., done: ... } 對象
// for...of 自動遍歷擁有 Iterator 接口的數據結構 let arr = ["a", "b", "c"]; for (let item of arr) { console.log(item); } // 輸出:a b c
類數組對象:存在數值鍵名和 length 屬性的對象
類數組對象部署 Iterator 方法:
// 方法一: NodeList.prototype[Symbol.iterator] = Array.prototype[Sybmol.iterator]; // 方法二: NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]; // for...of 遍歷類數組對象 let arrLike = { 0: "a", 1: "b", 2: "c", length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; for (let item of arrLike) { console.log(item); } // 輸出:a b c
對象(Object)沒有默認 Iterator 接口,因為對象屬性遍歷順序不確定,需開發者手動指定。
注意:
普通對象部署數組的 Symbol.iterator 方法,并無效果;
普通對象若 Symbol.iterator 方法對應的部署遍歷器生成函數(即返回一個遍歷器對象),解釋引擎會報錯。
var obj = {}; obj[Symbol.iterator] = () => 1; [...obj]; // TypeError: [] is not a function
for...of 遍歷普通對象的解決方法:
使用 Objet.keys 將對象鍵名生成一個數組,然后遍歷該數組;
Generator 函數重新包裝對象
let person = { name: "Ken", sex: "Male" } // Object.keys for (let key of Object.keys(person)) { console.log(`${key}: ${person[key]}`); } // Generator 包裝對象 function* entries(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } } for (let [key, value] of entries(person)) { console.log(`${key}: ${value}`); } // 輸出: // name: Ken // sex: MaleES6 的 Iterator 應用場景
解構賦值
擴展運算符
yield*
任何以數組為參數的遍歷的場景:
for...of
Array.from()
Map()/Set()/WeakMap()/WeakSet()
Promise.all()/Promise.race()
for...of 對比 for / for...in / forEachfor 循環 :需定義索引變量,指定循環終結條件。
for (let i = 0, len = arr.length; i < len; i++) { console.log(arr[i]); }
forEach: 無法中途跳出循環,break/return。
forEach(arr, function(item, index) { console.log(item, index); })
for...in:
只能獲取鍵名,不能獲取鍵值
以字符串為鍵名(但數組的鍵名為數值類型索引)
任意順序遍歷鍵名(???)
會遍歷手動添加的其它鍵(原型鏈上的鍵)
為遍歷對象設計,不適用數組
let triangle = {a: 1, b: 2, c: 3}; function ColoredTriangle() { this.color = "red"; } ColoredTriangle.prototype = triangle; let obj = new ColoredTriangle(); for (let prop in obj) { // 需手動判斷是否屬于自身屬性,而不是原型鏈屬性 if (obj.hasOwnProperty(prop)) { console.log(`obj.${prop} = ${obj[prop]}`); } } // 輸出:obj.color = red
for...of 較其它三者優點:
和 for...in 一樣簡潔,但沒有 for...in 的缺點;
不同于 forEach, 可使用 break/return/continue 退出循環;
提供了遍歷所有數據的統一接口
缺點:遍歷普通對象時,不能直接使用。
參考文章
《JavaScript 設計模式與開發實踐》
《阮一峰ES6入門:Iterator 和 for...of 循環》
本文首發Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創,有不當的地方歡迎指出。轉載請指明出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105230.html
摘要:單體模式有以下優點用來劃分命名空間,減少全局變量數量。通常我們使用操作符創建單體模式的三種選擇,讓構造函數總返回最初的對象使用全局對象來存儲該實例不推薦,容易全局污染。實現該工廠模式并不困難,主要是要找到能夠穿件所需類型對象的構造函數。 介紹 最近開始給自己每周訂個學習任務,學習結果反饋為一篇文章的輸出,做好學習記錄。 這一周(02.25-03.03)我定的目標是《JavaScri...
摘要:沒有顯示顯示顯示關鍵字迭代器生成器用于馬上退出代碼塊并保留現場,當執行迭代器的函數時,則能從退出點恢復現場并繼續執行下去。迭代器迭代器是一個擁有方法和方法的對象,通過函數不斷執行以關鍵字分割的代碼段,通過函數令分割的代碼段拋出異常。 一、前言 第一次看koajs的示例時,發現該語句 function *(next){..........
摘要:但實際中,內部迭代器和外部迭代器兩者并無優劣。迭代器并不只迭代數組迭代器模式不僅能迭代數組,還可以迭代一些類數組對象。晚安了,參考設計模式與開發實踐曾探本文作者本文鏈接迭代器模式設計模式與開發實踐閱讀筆記 迭代器模式:一個相對簡單的模式,目前絕大多數語言都內置了迭代器,以至于大家都不覺得這是一種設計模式 迭代器模式 迭代器模式指提供一種方法訪問一個聚合對象中的各個元素,而又不需要暴露該...
摘要:迭代器模式可以把迭代的過程從業務邏輯中分離出來,在使用迭代器模式后,即使不關心內部構造,也可以按順序訪問其他的每個元素。中的迭代器迭代器模式無非就是循環訪問聚合對象中的各個元素。目前絕大部分都內置了迭代器 迭代器模式指提供一種方法順序訪問一個聚合對象中的各個元素,而不需要暴露對象的內部。迭代器模式可以把迭代的過程從業務邏輯中分離出來,在使用迭代器模式后,即使不關心內部構造,也可以按順序...
摘要:迭代器模式就是按照順序訪問一個對象中元素,而不用暴露該對象的內部組成。迭代器模式就是將這個迭代實現從業務中分離出來。外部迭代器外部迭代器必須顯式地請求才會迭代下一個元素。 迭代器模式就是按照順序訪問一個對象中元素,而不用暴露該對象的內部組成。迭代器模式就是將這個迭代實現從業務中分離出來。 但實際開發中我們并不將他當成一個設計模式。 前瞻后顧 說起迭代器,想必對ES6有了解的同學應該不會...
閱讀 3243·2021-11-11 11:00
閱讀 2564·2019-08-29 11:23
閱讀 1440·2019-08-29 10:58
閱讀 2323·2019-08-29 10:58
閱讀 2952·2019-08-23 18:26
閱讀 2507·2019-08-23 18:18
閱讀 2038·2019-08-23 16:53
閱讀 3411·2019-08-23 13:13