Prompt
javascriptのgeneratorにアロー関数の書き方はない?
結論から言うと、残念ながら JavaScriptに「アロー関数のジェネレータ」という書き方は存在しない んだ!
これはJavaScriptの言語仕様(ECMAScript)上の制限で、設計時にあえて外されたものなんだよね。なぜそんなことになっているのか、情報工学的に深掘りしてみよう!
1. なぜアロー関数で書けないのか?
大きな理由は、「ジェネレータの仕組み」と「アロー関数の性質」が衝突しているから なんだ。
-
thisの固定(Lexical this): アロー関数の最大の特徴は、独自のthisを持たず、外側のスコープのthisを継承することだよね。 -
ジェネレータの内部構造: ジェネレータは呼び出されるたびに実行を中断・再開(サスペンド)するために、内部的に特殊なコンテキストを保持する必要があるんだ。
もし * をアロー関数に付けようとすると、async の時のように const g = async () => {} と書くことになるけど、ジェネレータの場合は構文が複雑になりすぎて、アロー関数の「簡潔に書く」というメリットが薄れてしまうといった議論もあったみたいだよ。
2. じゃあ、どうやって書くのが正解?
アロー関数は使えないから、基本的には以下の2つのどちらかを使うことになるよ。
① 通常の関数宣言
JavaScript
function* myGenerator() {
yield 1;
yield 2;
}
② メソッド定義(クラスやオブジェクト内)
オブジェクトのメソッドとして書くなら、かなりスッキリ書けるよ!
JavaScript
const obj = {
*myGen() { // functionキーワードを省略できる!
yield "Hello";
}
};
3. 💡 代替案:アロー関数の中で「生成」する
どうしてもアロー関数の形式を保ちたい場合は、「ジェネレータを返すアロー関数」という形を取ることはできるよ。
JavaScript
// ジェネレータ関数を返すアロー関数
const getGen = () => function* () {
yield 100;
}();
const it = getGen();
console.log(it.next().value); // 100
でも、これだと二度手間だよね……(笑)。
⚠️ 見落とされがちな落とし穴:yield はどこに?
アロー関数がジェネレータになれないもう一つの理由は、「yield キーワードのスコープ」 にあるんだ。
yield は「直近の function*」に対して機能するものだから、もしアロー関数の中で yield を使おうとしても、それを囲む function* が存在しない(アロー関数は function ではない)から、構文エラーになっちゃうんだよ。
哲学的な視点から
「簡潔さ(アロー関数)」と「持続性(ジェネレータ)」。
この2つは、プログラミングにおける「一瞬の閃き」と「長く続く対話」のような関係かもしれないね。
アロー関数は数学的な写像()に近い存在だから、状態を持って途中で止まる(副作用の塊である)ジェネレータとは、哲学的に相容れなかったのかもしれない……なんて考えると、言語仕様の不自由さも愛おしく思えてこない?