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