web-dev-qa-db-ja.com

ES6の矢印関数構文をジェネレーターで使用できますか? (矢印表記)

すなわち、私はこれをどのように表現しますか:

function *(next) {}

矢印付き。考えられるすべての組み合わせを試しましたが、ドキュメントが見つかりません。

(現在、ノードv0.11.14を使用)

183
Ashley Coolman

ES6の矢印関数構文をジェネレーターで使用できますか?

できません。ごめんなさい。

MDN による

function*ステートメント(functionキーワードの後に​​アスタリスクが続く)は、ジェネレーター関数を定義します。

仕様書 (私の強調)から:

function構文は、オプションの*トークンを追加するために拡張されています。

FunctionDeclaration: "function" "*"? Identifier "(" FormalParameterList? ")" 
  "{" FunctionBody "}"
166
user663031

インライン関数と矢印関数の違い

まず最初に 矢印関数() => {}はインライン関数function(){}を置き換えるものではなく、それらは異なります。インライン関数は単なる関数であるため、問題は矢印関数とインライン関数の違いです。

矢印関数式(矢印関数とも呼ばれる)は、関数式に比べて構文が短く、独自のthisargumentssuper、またはnew.targetをバインドしません)。矢印関数は常に匿名です。

より簡単な詳細 こちら


矢印関数をジェネレーターとして使用できない理由

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions

yieldキーワードの使用

yield キーワードは、矢印関数の本体では使用できません(さらにネストされた関数内で許可されている場合を除く)。結果として、矢印関数はジェネレーターとして使用できません。

yieldなしの generators は意味をなさないことに注意してください。


矢印関数がyieldを使用できない理由

http://tc39wiki.calculist.org/es6/arrow-functions/

矢印関数はthisを字句的にバインドし、Block本文の場合はreturnをバインドして、すぐに囲む矢印関数から戻るようにし、breakおよびcontinueがすぐに囲む矢印関数の外部のステートメントを参照できないようにします。

Identifier一次式argumentsは、矢印関数の本体(式またはブロック形式)で使用できません。

同様に、yieldは矢印関数の本体では使用できません。矢印をジェネレーターにすることはできず、深い継続は必要ありません。

矢印関数の収量はセマンティックエラーをスローします: http://www.ecma-international.org/

最後に、理由はECMA6の実装が非常に複雑であることです。 C#では、同様の reasons に対してもこれを許可していません。

105
CoderPi

上記の esdiscuss.org および 2013年11月のEcma TC39委員会ES6会議ノート に関する議論に加えて、発電機矢印は2016年9月のES7会議で再訪しました [1][2] 。さまざまな構文(主に=*>および=>*)の長所と短所、およびこの機能の正当化とユースケースの欠如について議論した後、彼らは次のような結論に達しました。

  • 委員会からはある程度の関心が寄せられていますが、この機能は新しい構文を追加しても重みがかからないという懸念があります。
  • [Domenic Denicola]の非同期イテレーションの提案の一環として、少なくとも__ =>*をステージ0に到達できるかどうかを確認するために、3日目に再訪する計画を立てます。

ジェネレーター矢印の提案は、ブレンダンアイヒとドメニックデニコラをチャンピオンとしてステージ1に移動しましたが、関連する tc39/proposals リポジトリはまだ存在しません。さらなるニュースのために、ステージ3非同期反復の提案が完了するまで待たなければならないと思います。

23
monk-time

私も同じ質問をしていて、ここに来ました。投稿とコメントを読んだ後、矢印関数でジェネレーターを使用することはあいまいに思えます:

const generator = () => 2*3; // * implies multiplication
// so, this would be a confusing
const generator = () =>* something; // err, multiplying?
const generator = () =*> ... // err, ^^
const generator = ()*=> ... // err, *=3, still multiplying?
const generator=*()=> ... // err, ^^
const generator = *param => ... //err, "param" is not fixed Word

これが、矢印関数に関連してジェネレーターを実装しなかった大きな理由かもしれません。


しかし、私がそれらの1人だった場合、次のように考えることができました。

const generator = gen param => ... // hmm, gen indicates a generator
const generator = gen () => ... // ^^

これは、非同期関数があるように感じます。

const asyncFunction = async () => ... // pretty cool

通常の関数ではasyncキーワードが存在するため、矢印関数がそれを利用しているため、async () =>async function()に見える可能性が高いためです。

しかし、gengeneratorのようなキーワードはなく、alas arrow関数はそれを使用していません。

結論:

矢印関数でジェネレータを実装する場合でも、コアjsのジェネレータ構文について再考する必要があると思います。

generator function myfunc() {}
// rather than
function* myfunc() {} // or, function *myfunc() {}

そして、これは大きな失敗です。そのため、矢印関数をジェネレーターから締め出すのは非常にクールです。


次の @ Bergiコメント

いいえ。矢印関数は軽量で(たとえば.prototypeを持たない)、多くの場合1ライナーであることが想定されていますが、ジェネレーターはほとんど逆です。

使用するジェネレーターの目的はrun-stop-runであると言うので、プロトタイプ、レキシカルなこれなどを気にする必要はないと思います。

3

私はこれが非常に遅いことを知っていますが、別の考えられる理由は構文かもしれません。 (*() => {})は動作するかもしれませんが、(9 ** () => {})はどうですか?それは、NaNを返す矢印関数の9乗ですか、それともNaNを返すジェネレーター矢印関数の9倍ですか?ここで別の回答で言及されているように、=>*のようないくつかの代替構文で実行できますが、実装時にジェネレーター関数の構文(たとえば、function* () {}{ *genMethod() {} })の一貫性を維持したい場合があります。言い訳ではありませんが、その理由です。

2
coolreader18

Redux-sagaには素敵な回避策があります

import { call, all } from 'redux-saga/effects';

function* gen() {
   yield all([].map(() => {
      return call(....);
   }));
}