Node v4 – Generator函式

whjin發表於2019-02-16

1、Generator簡介

基本概念

Generator函式有多種理解角度。從語法上,首先可以把它理解成,Generator函式是一個狀態機,封裝了多個內部狀態。

執行Generator函式會返回一個遍歷器物件,也就是說,Generator函式除了狀態機,還是一個遍歷器物件生成函式。返回的遍歷器物件,可以依次遍歷Generator函式內部的每一個狀態。

形式上,Generator函式是一個普通函式,但是有兩個特徵。一是,function命令與函式名之間有一個星號;二是,函式體內部使用yield語句,定義不同的內部狀態(yield語句在英語裡的意思就是“產出”)。

`use strict`;
function * helloWorldGenerator() {
    yield `hello`;
    yield `world`;
    return `ending`;
}
let hw = helloWorldGenerator();

上面程式碼定義了一個Generator函式helloWorldGenerator,它內部有兩個yield語句“hello”“world”,即該函式有三個狀態:helloworldreturn語句(結束執行)。

然後,Generator函式的呼叫方法與普通函式一樣,也是在函式名後面加上一對圓括號。不同的是,呼叫Generator函式後,該函式並不執行,返回的也不是函式執行結果,而是一個指向內部狀態的指標物件,遍歷器物件(Iterator Object)。

2、next方法

呼叫遍歷器物件的next方法,使得指標移向下一個狀態。也就是說,每次呼叫next方法,內部指標就從函式頭部或上一次停下來的地方開始執行,直到遇到下一個yield語句(或return語句)為止。換言之,Generator函式是分段執行的,yield語句是暫停執行的標記,而next方法可以恢復執行。

hw.next()
// { value: `hello`, done: false }
hw.next()
// { value: `world`, done: false }
hw.next()
// { value: `ending`, done: true }
hw.next()
// { value: undefined, done: true }

上面程式碼一共呼叫了四次next方法。

第一次呼叫,Generator函式開始執行,直到遇到第一個yield語句為止。next方法返回一個物件,它的value屬性就是當前yield語句的值hellodone屬性的值false,表示遍歷還沒有結束。

第二次呼叫,Generator函式從上次yield語句停下的地方,一直執行到下一個yield語句。next方法返回的物件的value屬性就是當前yield語句的值worlddone屬性的值false,表示遍歷還沒有結束。

第三次呼叫,Generator函式從上次yield語句停下的地方,一直執行到return語句(如果沒有return語句,就執行到函式結束)。next方法返回的物件的value屬性,就是緊跟在return語句後面的表示式的值(如果沒有return語句,則value屬性的值為undefined),done屬性的值true,表示遍歷已經結束。

第四次呼叫,此時Generator函式已經執行完畢,next方法返回物件的value屬性為undefineddone屬性為true。以後再呼叫next方法,返回的都是這個值。

總結一下,呼叫Generator函式,返回一個遍歷器物件,代表Generator函式的內部指標。以後,每次呼叫遍歷器物件的next方法,就會返回一個有著valuedone兩個屬性的物件。value屬性表示當前的內部狀態的值,是yield語句後面那個表示式的值;done屬性是一個布林值,表示是否遍歷結束。

3、yield*語句

用來在一個Generator函式裡面執行另一個Generator函式,我們需要用yield*語句。

如果yield命令後面跟的是一個遍歷器物件,需要在yield命令後面加上星號,表明它返回的是一個遍歷器物件。這被稱為yield*語句。

`use strict`;
function *anotherGenerator(i) {
    yield i + 1;
    yield i + 2;
    yield i + 3;
}
function *generator(i) {
    yield i;
    yield *anotherGenerator(i);
    yield i + 10;
}
let gen = generator(10);
console.log(gen.next().value);//10
console.log(gen.next().value);//11
console.log(gen.next().value);//12
console.log(gen.next().value);//13
console.log(gen.next().value);//20
console.log(gen.next().value);//undefined

執行結果就是使用一個遍歷器,遍歷了多個Generator函式,有遞迴的效果。

相關文章