function* 宣言
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2016.
Please take two minutes to fill out our short survey.
function*
宣言(function
キーワードにアスタリスクが付いたもの)は、 Generator
オブジェクトを返すジェネレーター関数を定義します。
ジェネレーター関数は GeneratorFunction
コンストラクターや、関数式の構文を使用して定義することもできます。
試してみましょう
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
}
メモ: ジェネレーター関数には、対応するアロー関数はありません。
引数
name
-
関数名。
param
省略可-
関数の形式上の引数の名前。
statements
-
関数の本体を構成する文。
解説
ジェネレーターは処理を抜け出したり、後から復帰したりすることができる関数です。ジェネレーターのコンテキスト(変数の値)は復帰しても保存されます。
JavaScript のジェネレーターは、特にプロミスと組み合わせることで、非同期プログラミングのための非常に強力なツールとなり、コールバック地獄や制御の逆転などのようなコールバックの問題を、完全に解決できるわけではないものの、軽減することができます。しかし、これらの問題は非同期関数を使用すると、さらにシンプルに解決することができます。
ジェネレーター関数を呼び出しても関数はすぐには実行されません。代わりにその関数のジェネレーターオブジェクトが返されます。イテレーターの next()
メソッドが呼び出されると、ジェネレーター関数の処理は、イテレーターから返された値を特定する最初の yield
演算子か、ほかのジェネレーター関数に委任する yield*
に達するまで実行されます。next()
メソッドは産出された値を含む value
プロパティと、ジェネレーターが最後の値を持つかを真偽値で示す done
プロパティを持つオブジェクトを返します。引数つきでnext()
を呼び出すと、ジェネレーター関数の実行が再開され、処理が停止していた yield
式を next()
の引数で置き換えます。
ジェネレーターで return
文が実行されると、ジェネレーターが終了します(つまり、それによって返されたオブジェクトの done
プロパティが true
に設定されます)。値が返された場合、それはジェネレーターによって返されたオブジェクトの value
プロパティとして設定されます。 return
文とよく似ていますが、ジェネレーターの内部でエラーが発生した場合は、ジェネレーターの本体の中でキャッチしない限り、ジェネレーターは終了します。
ジェネレーターが終了すると、それ以降の next()
の呼び出しでは、そのジェネレーターのコードは実行されず、 {value: undefined, done: true}
の形のオブジェクトが返されるだけです。
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();
// 最初の next の呼び出しで、関数の最初から、
// 最初の yield 文の前まで実行される。
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
式で定義されたジェネレーター
const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
ジェネレーターの例
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
}
仕様書
Specification |
---|
ECMAScript® 2026 Language Specification # sec-generator-function-definitions |
ブラウザーの互換性
関連情報
function* 式
-
GeneratorFunction
オブジェクト yield
yield*
-
Function
オブジェクト -
function
宣言 -
function
式 - 関数と関数スコープ
-
その他のウェブリソース:
- Regenerator an ES2015 generator compiler to ES5
- Forbes Lindesay: Promises and Generators: control flow utopia — JSConf EU 2013
- Task.js
- Iterating generators asynchronously