摘要:數(shù)據(jù)的層級(jí)意味著迭代數(shù)據(jù)結(jié)構(gòu)并提取它的數(shù)據(jù)。對(duì)于技術(shù)人而言技是單兵作戰(zhàn)能力,術(shù)則是運(yùn)用能力的方法。在前端娛樂圈,我想成為一名出色的人民藝術(shù)家。
聊聊 for of
說起 for of 相信每個(gè)寫過 JavaScript 的人都用過 for of ,平時(shí)我們用它做什么呢?大多數(shù)情況應(yīng)該就是遍歷數(shù)組了,當(dāng)然,更多時(shí)候,我們也會(huì)用 map() 或者 filer() 來遍歷一個(gè)數(shù)組。 但是就像我們標(biāo)題里面說的,它跟 Generator 能扯上什么關(guān)系呢?
首先我們想一個(gè)問題,為什么使用 for of 或者 map()/filer() 方法就可以遍歷一個(gè)數(shù)組 (或者類數(shù)組對(duì)象: Strings , Maps , Sets , arguments ) 呢? 為什么不能用他們來遍歷一個(gè)對(duì)象呢?
你能學(xué)到什么對(duì) for of 更深入的理解
iterator 到底是何方神圣?
數(shù)組也是對(duì)象,為什么不能用 for of 來遍歷對(duì)象呢?
如何實(shí)現(xiàn)對(duì)象的 for of?
Generator 又是何方神圣?他有什么用呢?
類數(shù)組對(duì)象的玄機(jī)在真正揭開謎底之前,站在 for of 的角度想一下,現(xiàn)在讓你去遍歷一個(gè)數(shù)組,你需要知道什么信息呢?
對(duì)應(yīng)下標(biāo)的值
是否遍歷結(jié)束的標(biāo)志
帶著這樣的思考,我們打印一個(gè)數(shù)組來看看這里面的玄機(jī):
const numbersArray = [1, 2, 3]; console.dir(numbersArray);
數(shù)組 (或者類數(shù)組對(duì)象: Strings , Maps , Sets , arguments ) 的原型中都實(shí)現(xiàn)了一個(gè)方法 Symbol.iterator,問題來了,那么這個(gè) Symbol.iterator 又有什么用呢? 拿出來試一下就知道了:
let iterator = numbersArray[Symbol.iterator](); // 我們把這個(gè) Symbol.iterator 打印一下看看里面到底有些什么 console.dir(iterator);
這里有一個(gè) next() 方法對(duì)嗎?執(zhí)行這個(gè) next() 方法:
iterator.next(); // 輸出 {value: 1, done: false} iterator.next(); // 輸出 {value: 2, done: false} iterator.next(); // 輸出 {value: 3, done: false} iterator.next(); // 輸出 {value: undefined, done: true}
請注意,當(dāng)下標(biāo)超出時(shí),value: undefined
我們發(fā)現(xiàn)這個(gè) iterator.next() 每次都返回了一個(gè)對(duì)象。這對(duì)象包含兩個(gè)信息:當(dāng)前下標(biāo)的值,以及遍歷是否結(jié)束的標(biāo)志。這印證了我們之前思考,有了這兩個(gè)信息,你作為 for of 函數(shù),也能打印出數(shù)組的每一項(xiàng)了不是嗎?
新的問題來了,iterator 到底是何方神圣呢?
iterator(迭代器) & The iterator protocol(迭代協(xié)議)聊到了 iterator 我們不得不先說一下 The iterator protocol(迭代協(xié)議)
" The iterable protocol allows JavaScript objects to define or customize their iteration behavior " - MDN
MDN 上是這么說的:The iterator protocol 允許 JavaScript 對(duì)象去定義或定制它們的迭代行為 ,所以上面出現(xiàn)的 Symbol.iterator 這個(gè)方法,就是數(shù)組對(duì)于這個(gè)協(xié)議的實(shí)現(xiàn)。那么按照這個(gè)協(xié)議,數(shù)組是怎么實(shí)現(xiàn)了一個(gè) iterator 呢?
"In JavaScript an iterator is an object which defines a sequence and potentially a return value upon its termination. More specifically an iterator is any object which implements the Iterator protocol by having a next() method which returns an object with two properties: value, the next value in the sequence; and done, which is true if the last value in the sequence has already been consumed. If value is present alongside done, it is the iterator"s return value." - MDN
這一大段看起來比較費(fèi)勁,簡單來說就像我們上一章節(jié)所印證的,它實(shí)現(xiàn)的方式是定義了一個(gè) next() 方法,而這個(gè) next() 方法每次被執(zhí)行都會(huì)返回一個(gè)對(duì)象: {value:xxx/undefined , done: true/false } 其中 value 代表的是當(dāng)前遍歷到的值,done 代表是否遍歷結(jié)束。
本小節(jié)回答了我們之前的提問: 為什么不能用 for of 來遍歷一個(gè)對(duì)象呢? 原因很簡單:JavaScript 的對(duì)象中沒有實(shí)現(xiàn)一個(gè)這樣的 iterator 。你可以打印一個(gè)對(duì)象來看看結(jié)果如何:
console.dir({ a: 1, b: 2 });
okay, 到這里如果就結(jié)束的話,那我們了解得還不夠深入,于是再問一個(gè)問題:
Why is there no built-in object iteration ? (為什么在 object 中沒有內(nèi)置迭代器呢? )
為什么在 object 中沒有內(nèi)置迭代器呢?對(duì)啊,為什么呢? 我們在各樣的場景中也需要來遍歷一個(gè)對(duì)象???為什么沒有內(nèi)置一個(gè)迭代器呢?要回答這個(gè)問題,我們得從另外一個(gè)角度出發(fā),了解一些基本的概念:
我們常常說遍歷對(duì)象,但是簡單來說,只會(huì)在兩種層級(jí)上來對(duì)一個(gè) JavaScript 對(duì)象進(jìn)行遍歷:
程序的層級(jí) - 什么意思呢?在程序?qū)蛹?jí)上,我們對(duì)一個(gè)對(duì)象進(jìn)行迭代,是在迭代展示其結(jié)構(gòu)的對(duì)象屬性。 可能還不是很好理解,舉個(gè)栗子:Array.prototype.length 這個(gè)屬性與對(duì)象的結(jié)構(gòu)相關(guān),但卻不是它的數(shù)據(jù)。
數(shù)據(jù)的層級(jí) - 意味著迭代數(shù)據(jù)結(jié)構(gòu)并提取它的數(shù)據(jù)。舉個(gè)栗子:我們在迭代一個(gè)數(shù)組的時(shí)候,迭代器是對(duì)于它的 每一個(gè)數(shù)據(jù)進(jìn)行迭代,如果 array = [a, b, c, d] 那么迭代器訪問到的是 1, 2, 3, 4。
明白了這個(gè)緣由,JavaScript 雖然不支持用 for of 來遍歷對(duì)象,但是提供了一個(gè) for in 方法來遍歷所有非 Symbol 類型并且是可枚舉的屬性。
標(biāo)準(zhǔn)不支持,如果我們就是要用 for-of 來遍歷對(duì)象呢?那我們可以任性的實(shí)現(xiàn)一個(gè)?。?/p>
Object.prototype[Symbol.iterator] = function*() { for (const [key, value] of Object.entries(this)) { yield { key, value }; } };
for (const { key, value } of { a: 1, b: 2, c: 3 }) { console.log(key, value); }
不知道你有沒有注意一個(gè)細(xì)節(jié),在我們?nèi)涡缘膶?shí)現(xiàn)一個(gè) iterator 的代碼中,我們用到了一個(gè)很奇怪的結(jié)構(gòu) function*() {} ,這個(gè)就是我們接下來要介紹的 Generator
Generators看到這個(gè)名字覺得很厲害哈,但其實(shí)很簡單,寫一個(gè) Generator 你只需要在函數(shù)名和 function 關(guān)鍵字中間加一個(gè) * 號(hào)就可以了。至于里面的 yield 是什么,后面會(huì)說的。
talk is cheap , show me the code ,用一個(gè)例子,簡單說一下概念。
我們現(xiàn)在定義了一個(gè)這樣的 Generator 叫做 gen
function* gen() { yield 1; yield 2; yield 3; yield 4; }
我們只能看到,這里面有 4 個(gè)語句,那打印一下看看唄:
這里發(fā)現(xiàn)了一個(gè)熟悉的函數(shù),next() 方法,我們把 gen 實(shí)例化一下,執(zhí)行一下它的 next() 來看看結(jié)果:
還是熟悉的味道,那么到這里,我們已經(jīng)知道,Generator 可以實(shí)例化出一個(gè) iterator ,并且這個(gè) yield 語句就是用來中斷代碼的執(zhí)行的,也就是說,配合 next() 方法,每次只會(huì)執(zhí)行一個(gè) yield 語句。
多說一句,針對(duì) Generator 本身,還有一個(gè)有意思的特性,yield 后面可以跟上另一個(gè) Generator 并且他們會(huì)按照次序執(zhí)行:
function* gen() { yield 1; yield* gen2(); return; } function* gen2() { yield 4; yield 5; } let iterator = gen(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());
結(jié)果很有意思不是嗎?而且 return 會(huì)終結(jié)整個(gè) Generator ,換句話說:寫在 return 后面的 yield 不會(huì)執(zhí)行。
Generator 有什么用?Generator 有什么用? 聰明的同學(xué)可能已經(jīng)猜到了,是的,它能夠中斷執(zhí)行代碼的特性,可以幫助我們來控制異步代碼的執(zhí)行順序:
例如有兩個(gè)異步的函數(shù) A 和 B, 并且 B 的參數(shù)是 A 的返回值,也就是說,如果 A 沒有執(zhí)行結(jié)束,我們不能執(zhí)行 B。
那這時(shí)候我們寫一段偽代碼:
function* effect() { const { param } = yield A(); const { result } = yield B(param); console.table(result); }
這時(shí)候我們?nèi)绻枰玫?result 那么我們就需要:
const iterator = effect() iterator.next() iterator.next()
執(zhí)行兩次 next() 得到結(jié)果,看起來很傻不是嗎?有沒有好的辦法呢?(廢話,肯定有?。?br>假設(shè)你在每次執(zhí)行 A() / B() 的請求結(jié)束之后,都會(huì)自動(dòng)執(zhí)行 next() 方法呢?這不就解決了嗎?
這樣的庫早就存在了,建議大家參考 co 的源碼,當(dāng)然你也可以通過閱讀 這篇文章 來看看,到底 Generator 是怎么玩的。
最后這里是 Dendoink ,奇舞周刊原創(chuàng)作者,掘金 [聯(lián)合編輯 / 小冊作者] 。
對(duì)于技術(shù)人而言:技 是單兵作戰(zhàn)能力,術(shù) 則是運(yùn)用能力的方法。得心應(yīng)手,出神入化就是 藝 。在前端娛樂圈,我想成為一名出色的人民藝術(shù)家。掃碼關(guān)注公眾號(hào) 前端惡霸 我在這里等你:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/104323.html
摘要:前言在學(xué)習(xí)前端的時(shí)候,我總是能聽到很多高級(jí)詞匯,比如今天會(huì)聊到的函數(shù)式編程高階函數(shù)。接下來我們看看,高階函數(shù)有可能會(huì)遇到的問題,又如何去解決。 前言 在學(xué)習(xí)前端的時(shí)候,我總是能聽到很多高級(jí)詞匯,比如今天會(huì)聊到的 函數(shù)式編程(Functional Programming) & 高階函數(shù) (Higher-order function) 。但是當(dāng)你真正的理解什么是 函數(shù)式編程 & 高階函數(shù) ...
摘要:你能學(xué)到什么如何使用實(shí)現(xiàn)異步編程異步編程的原理解析前言結(jié)合上一篇文章,我們來聊聊基礎(chǔ)原理說到異步編程,你想到的是和,但那也只是的語法糖而已。表示一個(gè)異步操作的最終狀態(tài)完成或失敗,以及其返回的值。至此實(shí)現(xiàn)異步操作的控制。 你能學(xué)到什么 如何使用 Generator + Promise 實(shí)現(xiàn)異步編程 異步編程的原理解析 前言 結(jié)合 上一篇文章 ,我們來聊聊 Generator 基礎(chǔ)原理...
摘要:我覺得那時(shí)他可能并沒有料到,這一規(guī)則的制定會(huì)讓整個(gè)前端發(fā)生翻天覆地的變化。前言 作為一名前端工程師,每天的清晨,你走進(jìn)公司的大門,回味著前臺(tái)妹子的笑容,摘下耳機(jī),泡上一杯茶,打開 Terminal 進(jìn)入對(duì)應(yīng)的項(xiàng)目目錄下,然后 npm run start / dev 或者 yarn start / dev 就開始了一天的工作。 當(dāng)你需要進(jìn)行時(shí)間的轉(zhuǎn)換只需要使用 dayjs 或者 momentj...
閱讀 2499·2021-11-23 09:51
閱讀 2542·2021-11-11 17:21
閱讀 3171·2021-09-04 16:45
閱讀 2460·2021-08-09 13:42
閱讀 2290·2019-08-29 18:39
閱讀 2962·2019-08-29 14:12
閱讀 1357·2019-08-29 13:49
閱讀 3434·2019-08-29 11:17