當前位置:
首頁 > 知識 > ES6 Generator 函數

ES6 Generator 函數

ES6 新引入了 Generator 函數,可以通過 yield 關鍵字,把函數的執行流掛起,為改變執行流程提供了可能,從而為非同步編程提供解決方案。 基本用法

Generator 函數組成

Generator 有兩個區分於普通函數的部分:

  • 一是在 function 後面,函數名之前有個 * ;
  • 函數內部有 yield 表達式。

其中 * 用來表示函數為 Generator 函數,yield 用來定義函數內部的狀態。

function* func(){

console.log("one");

yield "1";

console.log("two");

yield "2";

console.log("three");

return "3";

}

執行機制

調用 Generator 函數和調用普通函數一樣,在函數名後面加上()即可,但是 Generator 函數不會像普通函數一樣立即執行,而是返回一個指向內部狀態對象的指針,所以要調用遍歷器對象Iterator 的 next 方法,指針就會從函數頭部或者上一次停下來的地方開始執行。

f.next();

// one

// {value: "1", done: false}

f.next();

// two

// {value: "2", done: false}

f.next();

// three

// {value: "3", done: true}

f.next();

// {value: undefined, done: true}

第一次調用 next 方法時,從 Generator 函數的頭部開始執行,先是列印了 one ,執行到 yield 就停下來,並將yield 後邊表達式的值 "1",作為返回對象的 value 屬性值,此時函數還沒有執行完, 返回對象的 done 屬性值是 false。

第二次調用 next 方法時,同上步 。

第三次調用 next 方法時,先是列印了 three ,然後執行了函數的返回操作,並將 return 後面的表達式的值,作為返回對象的 value 屬性值,此時函數已經結束,多以 done 屬性值為true 。

第四次調用 next 方法時, 此時函數已經執行完了,所以返回 value 屬性值是 undefined ,done 屬性值是 true 。如果執行第三步時,沒有 return 語句的話,就直接返回 {value: undefined, done: true}。

函數返回的遍歷器對象的方法

next 方法

一般情況下,next 方法不傳入參數的時候,yield 表達式的返回值是 undefined 。當 next 傳入參數的時候,該參數會作為上一步yield的返回值。

function* sendParameter(){

console.log("strat");

var x = yield "2";

console.log("one:" + x);

var y = yield "3";

console.log("two:" + y);

console.log("total:" + (x + y));

}

next不傳參

var sendp1 = sendParameter();

sendp1.next();

// strat

// {value: "2", done: false}

sendp1.next();

// one:undefined

// {value: "3", done: false}

sendp1.next();

// two:undefined

// total:NaN

// {value: undefined, done: true}

next傳參

var sendp2 = sendParameter();

sendp2.next(10);

// strat

// {value: "2", done: false}

sendp2.next(20);

// one:20

// {value: "3", done: false}

sendp2.next(30);

// two:30

// total:50

// {value: undefined, done: true}

除了使用 next ,還可以使用 for... of 循環遍歷 Generator 函數生產的 Iterator 對象。

return 方法

return 方法返回給定值,並結束遍歷 Generator 函數。

return 方法提供參數時,返回該參數;不提供參數時,返回 undefined 。

function* foo(){

yield 1;

yield 2;

yield 3;

}

var f = foo();

f.next();

// {value: 1, done: false}

f.return("foo");

// {value: "foo", done: true}

f.next();

// {value: undefined, done: true}

throw 方法

throw 方法可以再 Generator 函數體外面拋出異常,再函數體內部捕獲。

var g = function* () {

try {

yield;

} catch (e) {

console.log("catch inner", e);

}

};

var i = g();

i.next();

try {

i.throw("a");

i.throw("b");

} catch (e) {

console.log("catch outside", e);

}

// catch inner a

// catch outside b

遍歷器對象拋出了兩個錯誤,第一個被 Generator 函數內部捕獲,第二個因為函數體內部的catch 函數已經執行過了,不會再捕獲這個錯誤,所以這個錯誤就拋出 Generator 函數體,被函數體外的 catch 捕獲。

yield* 表達式

yield* 表達式表示 yield 返回一個遍歷器對象,用於在 Generator 函數內部,調用另一個 Generator 函數。

function* callee() {

console.log("callee: " + (yield));

}

function* caller() {

while (true) {

yield* callee();

}

}

const callerObj = caller();

callerObj.next();

// {value: undefined, done: false}

callerObj.next("a");

// callee: a

// {value: undefined, done: false}

callerObj.next("b");

// callee: b

// {value: undefined, done: false}

// 等同於

function* caller() {

while (true) {

for (var value of callee) {

yield value;

}

}

}

使用場景

實現 Iterator

為不具備 Iterator 介面的對象提供遍歷方法。

function* objectEntries(obj) {

const propKeys = Reflect.ownKeys(obj);

for (const propKey of propKeys) {

yield [propKey, obj[propKey]];

}

}

const jane = { first: "Jane", last: "Doe" };

for (const [key,value] of objectEntries(jane)) {

console.log(`${key}: ${value}`);

}

// first: Jane

// last: Doe

Reflect.ownKeys() 返回對象所有的屬性,不管屬性是否可枚舉,包括 Symbol。

jane 原生是不具備 Iterator 介面無法通過 for... of遍歷。這邊用了 Generator 函數加上了 Iterator 介面,所以就可以遍歷 jane 對象了。

ES6 Generator 函數

打開今日頭條,查看更多圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

學習 HTML5 Canvas 這一篇文章就夠了
使用Spring-boot快速啟動Spring應用

TAG:程序員小新人學習 |