摘要:函數(shù)從暫停狀態(tài)到恢復運行,它的上下文狀態(tài)是不變的。也就是說,可以在函數(shù)運行的不同階段,從外部向內(nèi)部注入不同的值,從而調(diào)整函數(shù)行為。循環(huán)循環(huán)可以自動遍歷函數(shù)時生成的對象,且此時不再需要調(diào)用方法。
基本概念
狀態(tài)機,封裝了多個內(nèi)部狀態(tài);
返回一個遍歷器對象,通過改對象可以一次遍歷Generator函數(shù)內(nèi)部的每一個狀態(tài)
帶*號,yeild表達式定義不同的內(nèi)部狀態(tài);
調(diào)用 Generator 函數(shù)后,該函數(shù)并不執(zhí)行,返回的也不是函數(shù)運行結(jié)果,而是一個指向內(nèi)部狀態(tài)的指針對象,也就是遍歷器對象;
Generator 函數(shù)是分段執(zhí)行的,yield表達式是暫停執(zhí)行的標記,而next方法可以恢復執(zhí)行;
暫停標志
next()方法允許邏輯
遇到y(tǒng)ield表達式,就暫停執(zhí)行后面的操作,并將緊跟在yield后面的那個表達式的值,作為返回的對象的value屬性值;
下一次調(diào)用next方法時,再繼續(xù)往下執(zhí)行,直到遇到下一個yield表達式;
沒有再遇到新的yield表達式,就一直運行到函數(shù)結(jié)束,直到return語句為止,并將return語句后面的表達式的值,作為返回的對象的value屬性值;
如果該函數(shù)沒有return語句,則返回的對象的value屬性值為undefined;
yield表達式只能用在 Generator 函數(shù)里面,用在其他地方都會報錯。
var arr = [1, [[2, 3], 4], [5, 6]]; var flat = function* (a) { a.forEach(function (item) { if (typeof item !== "number") { yield* flat(item); } else { yield item; //forEach()的參數(shù)是一個普通函數(shù)使用yield會報錯,可以使用for循環(huán)解決這個問題 } }); }; for (var f of flat(arr)){ console.log(f); }
使用for循環(huán)改正
var arr = [1, [[2, 3], 4], [5, 6]]; var flat = function* (a) { var length = a.length; for (var i = 0; i < length; i++) { var item = a[i]; if (typeof item !== "number") { yield* flat(item); } else { yield item; } } }; for (var f of flat(arr)) { console.log(f); }// 1, 2, 3, 4, 5, 6
yield表達式如果用在另一個表達式之中,必須放在圓括號里面;
yield表達式用作函數(shù)參數(shù)或放在賦值表達式的右邊,可以不加括號
與Iterator的關(guān)系可以把 Generator 賦值給對象的Symbol.iterator屬性,從而使得該對象具有 Iterator 接口
var myIterable = {}; myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable] // [1, 2, 3]next()方法的參數(shù)
yield表達式本身沒有返回值,或者說總是返回undefined。next方法可以帶一個參數(shù),該參數(shù)就會被當作上一個yield表達式的返回值。
function* f() { for(var i = 0; true; i++) { var reset = yield i; if(reset) { i = -1; } } } var g = f(); g.next() // { value: 0, done: false } g.next() // { value: 1, done: false } g.next(true) // { value: 0, done: false }
Generator 函數(shù)從暫停狀態(tài)到恢復運行,它的上下文狀態(tài)(context)是不變的。通過next方法的參數(shù),就有辦法在 Generator 函數(shù)開始運行之后,繼續(xù)向函數(shù)體內(nèi)部注入值。也就是說,可以在 Generator 函數(shù)運行的不同階段,從外部向內(nèi)部注入不同的值,從而調(diào)整函數(shù)行為。
分析以下代碼允許的結(jié)果:
function* foo(x) { var y = 2 * (yield (x + 1)); var z = yield (y / 3); return (x + y + z); } var a = foo(5); a.next() // Object{value:6, done:false} a.next() // Object{value:NaN, done:false} a.next() // Object{value:NaN, done:true} var b = foo(5); b.next() // { value:6, done:false } b.next(12) // { value:8, done:false } b.next(13) // { value:42, done:true }
next()傳參,參數(shù)代表上一次yeild表達式返回的值,因此第一次使用next()傳參是無效的;
function* dataConsumer() { console.log("Started"); console.log(`1. ${yield}`); console.log(`2. ${yield}`); return "result"; } let genObj = dataConsumer(); genObj.next(); // Started genObj.next("a") // 1. a genObj.next("b") // 2. b
如果想第一次調(diào)用next()方法就能夠輸入值,可以在Genrator函數(shù)外再包一層
function wrapper(generatorFunction) { return function (...args) { let generatorObject = generatorFunction(...args); generatorObject.next(); return generatorObject; }; } const wrapped = wrapper(function* () { console.log(`First input: ${yield}`); return "DONE"; }); wrapped().next("hello!")// First input: hello!
上述代碼在wrapper函數(shù)中,首先調(diào)用一次next方法,再返回遍歷器對象。當用戶自己調(diào)用next方法時,看起來就像是第一次調(diào)用,但實際上,這是第二次調(diào)用next方法。
for...of循環(huán)for...of循環(huán)可以自動遍歷 Generator 函數(shù)時生成的Iterator對象,且此時不再需要調(diào)用next方法。
function* foo() { yield 1; yield 2; yield 3; yield 4; yield 5; return 6; } for (let v of foo()) { console.log(v); } // 1 2 3 4 5
這里需要注意,一旦next方法的返回對象的done屬性為true,for...of循環(huán)就會中止;
Generator給對象添加Iterator方法一
function* objectEntries(obj) { let propKeys = Reflect.ownKeys(obj); for (let propKey of propKeys) { yield [propKey, obj[propKey]]; } } let jane = { first: "Jane", last: "Doe" }; for (let [key, value] of objectEntries(jane)) { console.log(`${key}: ${value}`); } // first: Jane // last: Doe
方法二將 Generator 函數(shù)加到對象的Symbol.iterator屬性上面。
function* objectEntries() { let propKeys = Object.keys(this); for (let propKey of propKeys) { yield [propKey, this[propKey]]; } } let jane = { first: "Jane", last: "Doe" }; jane[Symbol.iterator] = objectEntries; for (let [key, value] of jane) { console.log(`${key}: ${value}`); } // first: Jane // last: Doe
【完】
作者簡介:鄭佳歡,蘆葦科技web前端實習生,公司作品:口紅挑戰(zhàn)網(wǎng)紅小游戲、服務(wù)端渲染官網(wǎng)。擅長網(wǎng)站建設(shè)、公眾號開發(fā)、微信小程序開發(fā)、小游戲、公眾號開發(fā),專注于前端領(lǐng)域框架、交互設(shè)計、圖像繪制、數(shù)據(jù)分析等研究。 訪問 www.talkmoney.cn 了解更多
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104506.html
摘要:返回的遍歷器對象,可以依次遍歷函數(shù)內(nèi)部的每一個狀態(tài)。由于函數(shù)就是遍歷器生成函數(shù),因此可以把賦值給對象的屬性,從而使得該對象具有接口。函數(shù)從暫停狀態(tài)恢復運行,它的上下文狀態(tài)時不變的。從語義上講,第一個方法用來啟動遍歷器對象,所以不用帶有參數(shù)。 基本概念 Generator函數(shù)是ES6提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同。Generator函數(shù)有多種理解角度。語法上,首先...
摘要:以下展示它是如何工作的函數(shù)使用構(gòu)造函數(shù)創(chuàng)建一個新的對象,并立即將其返回給調(diào)用者。在傳遞給構(gòu)造函數(shù)的函數(shù)中,我們確保傳遞給,這是一個特殊的回調(diào)函數(shù)。 本系列文章為《Node.js Design Patterns Second Edition》的原文翻譯和讀書筆記,在GitHub連載更新,同步翻譯版鏈接。 歡迎關(guān)注我的專欄,之后的博文將在專欄同步: Encounter的掘金專欄 知乎專欄...
摘要:如果你已經(jīng)理解基礎(chǔ)可以直接跳過這部分和語法部分,直接看深入理解的部分。的參數(shù)可以傳入一個參數(shù),來作為上一次的表達式的返回值,就像我們上面說的會讓等于。 這篇文章旨在幫你真正了解Generator,文章較長,不過如果能花時間耐心看完,相信你已經(jīng)能夠完全理解generator 為什么要用generator 在前端開發(fā)過程中我們經(jīng)常需要先請求后端的數(shù)據(jù),再用拿來的數(shù)據(jù)進行使用網(wǎng)頁頁面渲染等操...
摘要:最后,調(diào)用這個函數(shù),得到一個遍歷器對象并賦值給變量。值得注意的是如果函數(shù)內(nèi)部沒有部署代碼塊,那么遍歷器對象的方法拋出的錯誤,將被外部代碼塊捕獲。 本文已同步至我的個人主頁。歡迎訪問查看更多內(nèi)容!如有錯誤或遺漏,歡迎隨時指正探討!謝謝大家的關(guān)注與支持! 一、什么是Generator函數(shù) Generator函數(shù)是ES6標準中提出的一種異步編程的解決方案。這種函數(shù)與普通函數(shù)最大的區(qū)別在于它可...
摘要:語法上,首先可以把它理解成,函數(shù)是一個狀態(tài)機,封裝了多個內(nèi)部狀態(tài)。返回的遍歷器對象,可以依次遍歷函數(shù)內(nèi)部的每一個狀態(tài)。 寫在前面: 這一篇是關(guān)于ES6中生成器函數(shù)相關(guān)總結(jié)和理解... Generator函數(shù)的定義 在阮一峰老師的書中的說法是: Generator 函數(shù)有多種理解角度。語法上,首先可以把它理解成,Generator 函數(shù)是一個狀態(tài)機,封裝了多個內(nèi)部狀態(tài)。執(zhí)行 Gener...
閱讀 3025·2021-11-16 11:42
閱讀 3679·2021-09-08 09:36
閱讀 957·2019-08-30 12:52
閱讀 2494·2019-08-29 14:12
閱讀 784·2019-08-29 13:53
閱讀 3597·2019-08-29 12:16
閱讀 654·2019-08-29 12:12
閱讀 2480·2019-08-29 11:16