function*
function* 宣告會建立一個新的生成器函式到給定名稱的繫結。生成器函式可以暫停執行,之後再恢復執行,它的上下文(變數繫結)會在多次重新進入時儲存下來。
你也可以使用function* 表示式定義生成器函式。
試一試
function* generator(i) {
yield i;
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value);
// Expected output: 10
console.log(gen.next().value);
// Expected output: 20
語法
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
注意:生成器函式沒有對應的箭頭函式。
注意:function 和 * 是獨立的詞法單元,因此它們可以被空格或行終止符分隔。
引數
name-
函式名稱。
param可選-
函式形式引數的名稱。有關引數的語法,請參閱函式參考。
statements可選-
構成函式體的語句。
描述
function* 宣告建立一個 GeneratorFunction 物件。每次呼叫生成器函式時,它都會返回一個新的 Generator 物件,該物件符合 迭代器協議。生成器函式的執行會在某個位置暫停,最初是在函式體的最開始。生成器函式可以被多次呼叫以同時建立多個生成器;每個生成器都維護自己的生成器函式執行上下文,並且可以獨立地執行。
生成器允許雙向控制流:控制流可以在生成器函式(被呼叫者)及其呼叫者之間根據雙方意願多次傳遞。控制流可以透過呼叫生成器的方法從呼叫者流向被呼叫者:next()、throw() 和 return()。控制流可以透過使用 return 或 throw 或執行所有語句正常退出函式,或者透過使用 yield 和 yield* 表示式從被呼叫者流向呼叫者。
當呼叫生成器的 next() 方法時,生成器函式的函式體將執行,直到發生以下情況之一:
- 一個
yield表示式。在這種情況下,next()方法返回一個物件,該物件具有一個包含生成值的value屬性和一個始終為false的done屬性。下次呼叫next()時,yield表示式將評估為傳遞給next()的值。 - 一個
yield*,委託給另一個迭代器。在這種情況下,此呼叫以及後續對生成器進行的任何next()呼叫都與對委託迭代器呼叫next()相同,直到委託迭代器完成。 - 一個
return語句(未被try...catch...finally捕獲),或控制流的結束(這意味著隱式return undefined)。在這種情況下,生成器已完成,next()方法返回一個物件,該物件具有一個包含返回值的value屬性和一個始終為true的done屬性。任何進一步的next()呼叫都不會產生任何效果,並且始終返回{ value: undefined, done: true }。 - 函式內部丟擲的錯誤,透過
throw語句或未處理的異常。next()方法丟擲該錯誤,生成器完成。任何進一步的next()呼叫都不會產生任何效果,並且始終返回{ value: undefined, done: true }。
當呼叫生成器的 throw() 方法時,其作用就像在生成器主體當前暫停的位置插入了一個 throw 語句。類似地,當呼叫生成器的 return() 方法時,其作用就像在生成器主體當前暫停的位置插入了一個 return 語句。除非生成器函式透過 try...catch...finally 捕獲了完成,否則這兩種方法通常都會終止生成器。
生成器曾經是非同步程式設計的一種正規化,透過實現控制反轉來避免回撥地獄。如今,這種用例已透過更簡單的非同步函式模型和Promise物件解決。然而,生成器仍然對許多其他任務很有用,例如以簡單明瞭的方式定義迭代器。
function* 宣告的行為類似於 function 宣告——它們被提升到其作用域的頂部,可以在其作用域中的任何位置呼叫,並且只能在特定上下文中重新宣告。
示例
基本示例
function* idMaker() {
let index = 0;
while (true) {
yield index++;
}
}
const gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// …
使用 yield* 的示例
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
const 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
向生成器傳遞引數
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
const gen = logGenerator();
// the first call of next executes from the start of the function
// until the first yield statement
gen.next(); // 0
gen.next("pretzel"); // 1 pretzel
gen.next("california"); // 2 california
gen.next("mayonnaise"); // 3 mayonnaise
生成器中的 return 語句
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
const gen = yieldAndReturn();
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
作為物件屬性的生成器
const someObj = {
*generator() {
yield "a";
yield "b";
},
};
const gen = someObj.generator();
console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: undefined, done: true }
作為物件方法的生成器
class Foo {
*generator() {
yield 1;
yield 2;
yield 3;
}
}
const f = new Foo();
const gen = f.generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
作為計算屬性的生成器
class Foo {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
}
const SomeObj = {
*[Symbol.iterator]() {
yield "a";
yield "b";
},
};
console.log(Array.from(new Foo())); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'a', 'b' ]
生成器不可構造
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor
生成器示例
function* powers(n) {
// Endless loop to generate
for (let current = n; ; current *= n) {
yield current;
}
}
for (const power of powers(2)) {
// Controlling generator
if (power > 32) {
break;
}
console.log(power);
// 2
// 4
// 8
// 16
// 32
}
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-generator-function-definitions |
瀏覽器相容性
載入中…
另見
- 函式指南
- 迭代器和生成器指南
- 函式
GeneratorFunctionfunction*表示式functionasync functionasync function*- 迭代協議
yieldyield*Generator- GitHub 上的 Regenerator
- Promises 和 Generators:控制流烏托邦 — Forbes Lindesay 在 JSConf 上的演講 (2013)
- GitHub 上的 Task.js
- 你不知道的 JS:非同步與效能,第 4 章:生成器 — Kyle Simpson