function*

Baseline 已廣泛支援

此特性已非常成熟,可在多種裝置和瀏覽器版本上使用。自 ⁨2016 年 9 月⁩以來,它已在各大瀏覽器中可用。

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

語法

js
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()。控制流可以透過使用 returnthrow 或執行所有語句正常退出函式,或者透過使用 yieldyield* 表示式從被呼叫者流向呼叫者。

當呼叫生成器的 next() 方法時,生成器函式的函式體將執行,直到發生以下情況之一:

  • 一個 yield 表示式。在這種情況下,next() 方法返回一個物件,該物件具有一個包含生成值的 value 屬性和一個始終為 falsedone 屬性。下次呼叫 next() 時,yield 表示式將評估為傳遞給 next() 的值。
  • 一個 yield*,委託給另一個迭代器。在這種情況下,此呼叫以及後續對生成器進行的任何 next() 呼叫都與對委託迭代器呼叫 next() 相同,直到委託迭代器完成。
  • 一個 return 語句(未被 try...catch...finally 捕獲),或控制流的結束(這意味著隱式 return undefined)。在這種情況下,生成器已完成,next() 方法返回一個物件,該物件具有一個包含返回值的 value 屬性和一個始終為 truedone 屬性。任何進一步的 next() 呼叫都不會產生任何效果,並且始終返回 { value: undefined, done: true }
  • 函式內部丟擲的錯誤,透過 throw 語句或未處理的異常。next() 方法丟擲該錯誤,生成器完成。任何進一步的 next() 呼叫都不會產生任何效果,並且始終返回 { value: undefined, done: true }

當呼叫生成器的 throw() 方法時,其作用就像在生成器主體當前暫停的位置插入了一個 throw 語句。類似地,當呼叫生成器的 return() 方法時,其作用就像在生成器主體當前暫停的位置插入了一個 return 語句。除非生成器函式透過 try...catch...finally 捕獲了完成,否則這兩種方法通常都會終止生成器。

生成器曾經是非同步程式設計的一種正規化,透過實現控制反轉來避免回撥地獄。如今,這種用例已透過更簡單的非同步函式模型和Promise物件解決。然而,生成器仍然對許多其他任務很有用,例如以簡單明瞭的方式定義迭代器

function* 宣告的行為類似於 function 宣告——它們被提升到其作用域的頂部,可以在其作用域中的任何位置呼叫,並且只能在特定上下文中重新宣告。

示例

基本示例

js
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* 的示例

js
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

向生成器傳遞引數

js
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 語句

js
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 }

作為物件屬性的生成器

js
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 }

作為物件方法的生成器

js
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 }

作為計算屬性的生成器

js
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' ]

生成器不可構造

js
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor

生成器示例

js
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

瀏覽器相容性

另見