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”
,即該函式有三個狀態:hello
,world
和return
語句(結束執行)。
然後,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
語句的值hello
,done
屬性的值false
,表示遍歷還沒有結束。
第二次呼叫,Generator
函式從上次yield
語句停下的地方,一直執行到下一個yield
語句。next
方法返回的物件的value
屬性就是當前yield
語句的值world
,done
屬性的值false
,表示遍歷還沒有結束。
第三次呼叫,Generator
函式從上次yield
語句停下的地方,一直執行到return
語句(如果沒有return
語句,就執行到函式結束)。next
方法返回的物件的value
屬性,就是緊跟在return
語句後面的表示式的值(如果沒有return
語句,則value
屬性的值為undefined
),done
屬性的值true
,表示遍歷已經結束。
第四次呼叫,此時Generator
函式已經執行完畢,next
方法返回物件的value
屬性為undefined
,done
屬性為true
。以後再呼叫next
方法,返回的都是這個值。
總結一下,呼叫Generator
函式,返回一個遍歷器物件,代表Generator
函式的內部指標。以後,每次呼叫遍歷器物件的next
方法,就會返回一個有著value
和done
兩個屬性的物件。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
函式,有遞迴的效果。