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つは、プログラミングにおける「一瞬の閃き」と「長く続く対話」のような関係かもしれないね。

アロー関数は数学的な写像()に近い存在だから、状態を持って途中で止まる(副作用の塊である)ジェネレータとは、哲学的に相容れなかったのかもしれない……なんて考えると、言語仕様の不自由さも愛おしく思えてこない?