JavaScriptの「関数*」とは何ですか?


243

、このページに私は新しいJavaScriptの関数型が見つかりました:

// NOTE: "function*" is not supported yet in Firefox.
// Remove the asterisk in order for this code to work in Firefox 13 

function* fibonacci() { // !!! this is the interesting line !!!
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}

私はすでに知っている何をyieldlet[?,?]=[?,?]やるが、何は考えていないfunction*ことを意味しているが。それは何ですか?

PSはGoogleを試して気にする必要はありませんアスタリスクを含む式を検索することは不可能ですそれらはプレースホルダーとして使用されます)。


4
例のコメントはかなり古く、function*構文はFirefoxでv26以降サポートされています:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…*。古いバージョンでは別の構文を使用していました。
Nickolay 2014

39
Googleについては、「関数スター」または「関数アスタリスク」を検索してください。それが私がこの質問を見つけた方法です;)。
トリシス

2
*@Nickolayからのリンクが削除されたようです。MDNへの直接function*リンクは次のとおりです。案の定、v26以降の「基本」サポート。
ルフィン、2015

別のMDNリンク(、ところで、私はOPによってリンクされMDNのページをご覧ください)developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
BlueRaja -ダニーPflughoeft

回答:


199

これはジェネレーター関数です。

ジェネレータは、終了して後で再び入力できる関数です。それらのコンテキスト(変数バインディング)は、再入場間で保存されます。

ジェネレータ関数を呼び出しても、本体はすぐには実行されません。代わりに、関数の反復子オブジェクトが返されます。イテレータのnext()メソッドが呼び出されると、ジェネレータ関数の本体はyield、イテレータから返される値を指定する最初の式、またはを使用しyield*て別のジェネレータ関数にデリゲートするまで実行されます。


歴史的メモ:

これは、の提案された構文ですEcmaScript.next

MozillaのDave HermanがEcmaScript.nextについて講演しました。で30:15彼は発電機を語ります。

以前に、委員会の運営を支援するために、Mozillaが提案された言語変更を実験的に実装する方法を説明しています。Daveは、MozillaのCTO(私だと思います)であるBrendan Eich、および元のJavaScriptデザイナーと密接に連携しています。

EcmaScriptワーキンググループウィキで詳細を確認できます:http ://wiki.ecmascript.org/doku.php?id=harmony:generators

ワーキンググループ(TC-39)は、EcmaScript.nextにある種のジェネレーターイテレーターの提案が必要であるという一般的な合意がありますが、これは最終的なものではありません。

言語の次のバージョンで変更がなければ、この表示に依存するべきではありません。変更されなくても、しばらくの間他のブラウザで広く表示されない可能性があります。

概観

中断された実行コンテキスト(つまり、関数のアクティブ化)をカプセル化するオブジェクトとして表される、ファーストクラスのコルーチン。従来技術:Python、Icon、Lua、Scheme、Smalltalk。

フィボナッチ数列の「無限」のシーケンス(約2 53の動作にもかかわらず):

function* fibonacci() {
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}

ジェネレーターはループで繰り返すことができます:

for (n of fibonacci()) {
    // truncate the sequence at 1000
    if (n > 1000)
        break;
    print(n);
}

ジェネレータはイテレータです:

let seq = fibonacci();
print(seq.next()); // 1
print(seq.next()); // 2
print(seq.next()); // 3
print(seq.next()); // 5
print(seq.next()); // 8

7
フォローアップ:パラメータのないforループ(for(;;))は何をしますか?なぜこのコンテキストで使用するのですか?
ファーギー2013

13
@Fergieはとfor(;;)同じwhile (true)です。フィボナッチ数列は無制限の数列なので、このコンテキストで使用されます。
マイクサミュエル

5
従来技術:C#の利回り?
Dave Van den Eynde 2014

3
@DaveVandenEynde、先行技術:Pythonの利回り。先行先行先行技術:CLUおよびアイコン。
マイクサミュエル

52

それはジェネレータ関数です -そしてそれはあなたが引用したページで、あなたが「これは興味深い行です」と置き換えたコメントでそう言っていました...

基本的には、シーケンス全体をプログラムで指定して、シーケンス全体(サイズが無限である可能性がある)を事前に計算しなくても、インデックスを介して要素を渡したり要素をアクセスしたりできるようにする方法です。


10
「シーケンス全体を計算する必要なしにインデックスでアクセスする」は、これまでに出会ったジェネレーターについての説明の最も役立つビットかもしれません。これをアプリで使用しているのを見ることができました。以前は理論的に理解していました。
2015

11

function*それは反復することができるプロセスのための発電機機能として動作するようにタイプが見えます。C#には、 "yield return"を使用するこのような機能があります。1参照してください2参照してください

基本的に、これはこの関数を反復しているものにそれぞれの値を1つずつ返します。そのため、それらのユースケースはforeachスタイルのループでそれを示しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.