← 返回首页
function* 宣言 - JavaScript | MDN

このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

View in English Always switch to English

function* 宣言

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2016年9月.

function* 宣言は、新しいジェネレーター関数を指定された名前へのバインドとして作成します。ジェネレーター関数は、脱出した後でそのコンテキスト(変数のバインド)を保存したまま再入することが可能です。

ジェネレーター関数は function* 式を使って定義することもできます。

In this article

試してみましょう

function* generator(i) { yield i; yield i + 10; } const gen = generator(10); console.log(gen.next().value); // 予想される結果: 10 console.log(gen.next().value); // 予想される結果: 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() を呼んで移行します。制御フローは、return や throw を使用して通常通り関数を終了させたり、すべての文を実行したり、yield および yield* 式を使用したりすることで、呼び出し側から呼び出し先へ進むことができます。

ジェネレーターの next() メソッドが呼び出されると、ジェネレーター関数の本体は次のいずれかになるまで実行されます。

  • yield 式。この場合、next() メソッドは、yield で返された値を含む 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 によって完了をキャッチしない限り、通常はジェネレーターを完了させます。

ジェネレーターはかつて非同期プログラミングのパラダイムであり、コールバック地獄制御の反転によって避けることができました。現在では、この場合の解決はよりシンプルな async 関数モデルと 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(); // 最初の next の呼び出しで、関数の最初から、 // 最初の yield 文の前まで実行される。 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) { // 生成の無限ループ for (let current = n; ; current *= n) { yield current; } } for (const power of powers(2)) { // ジェネレーターを制御 if (power > 32) { break; } console.log(power); // 2 // 4 // 8 // 16 // 32 }

仕様書

Specification
ECMAScript® 2027 Language Specification
# sec-generator-function-definitions

ブラウザーの互換性

Enable JavaScript to view this browser compatibility table.

関連情報