形式上,Generator 函數是一個普通函數,但是有兩個特徵。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield語句,定義不同的內部狀態
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
// 調用方式一:
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
// 調用方式二:
for( let x of hw){
}
不同的是,調用Generator函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,我們可以通過調用 next 方法,使得指針移向下一個狀態
// next給函數內變量傳值
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 函數f,如果next方法沒有參數,每次運行到yield語句,變量reset的值總是undefined。當next方法帶一個參數true時,變量reset就被重置爲這個參數(即true),因此i會等於-1,下一輪循環就會從-1開始遞增。
這個功能有很重要的語法意義。Generator 函數從暫停狀態到恢復運行,它的上下文狀態(context)是不變的。通過next方法的參數,就有辦法在 Generator 函數開始運行之後,繼續向函數體內部注入值。也就是說,可以在 Generator 函數運行的不同階段,從外部向內部注入不同的值,從而調整函數行爲。這個用處在其用來實現 async/await 至關重要。