Puis-je utiliser la syntaxe de la fonction flèche d'ES6 avec des générateurs? (notation fléchée)


243

c'est-à-dire comment exprimer ceci:

function *(next) {}

avec des flèches. J'ai essayé toutes les combinaisons auxquelles je pouvais penser et je ne trouve aucune documentation à ce sujet.

(utilise actuellement le nœud v0.11.14)


5
Tu ne peux pas. Désolé. "L' function*instruction (mot-clé de fonction suivi d'un astérisque) définit une fonction de générateur."

2
Notez qu'il y a eu une discussion assez longue sur ce sujet sur esdiscuss.org .
voithos

4
Que comptez-vous param*=>{ }faire?
CoderPi

4
vous savez que ce function(){}n'est pas la même chose que ()=>{}?
CoderPi

8
" est-ce vraiment que les générateurs ES6 sont 2 pas en avant et 1 pas en arrière? " - non, les générateurs ne peuvent que faire un pas en avant :-)
Bergi

Réponses:


231

Puis-je utiliser la syntaxe de la fonction flèche d'ES6 avec des générateurs?

Tu ne peux pas. Désolé.

Selon MDN

L' function*instruction ( functionmot-clé suivi d'un astérisque) définit une fonction de générateur.

À partir d'un document de spécification (c'est moi qui souligne):

La syntaxe de la fonction est étendue pour ajouter un *jeton facultatif :

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

175
Je me sens comme un défaut de conception.
Jonathon

23
@Jonathon: Non. Les fonctions fléchées sont censées être légères (et n'en ont pas .prototypepar exemple) et souvent à une ligne, tandis que les générateurs sont à peu près le contraire.
Bergi

38
J'ai déjà rencontré quelques scénarios où un générateur avec lequel je jouais avait besoin d'un accès au précédent this, et j'ai dû écrire le let self = thishack pour y accéder à l'intérieur du générateur. La syntaxe lexicale portée + flèche aurait été bien. Malheureux, mais pas exactement la fin du monde.
dvlsg

3
Un contexte supplémentaire autour de cela à esdiscuss
Nick Tomlin

20
@Bergi le raisonnement derrière les fonctions fléchées est beaucoup plus compliqué que cela. Ce n'est pas vraiment de la brièveté. Les fonctions fléchées n'ont pas besoin d'être légères - il est vrai qu'il existe une syntaxe de corps à instruction unique facultative, mais alors quoi. De nombreuses personnes utilisent des flèches pour toutes les définitions de fonction, à l'exception des méthodes de classe, et rétrogradent le functionmot - clé comme étant une «mauvaise partie» du langage. Il y a de bonnes raisons de le faire. Pour ces personnes, le manque de générateurs de flèches est une incohérence gênante.
callum

132

La différence entre les fonctions en ligne et les fonctions fléchées

Tout d'abord fonctions Flèche () => {} ne sont pas conçues pour remplacer les fonctions Inline function(){}et elles sont différentes. Les fonctions en ligne sont simplement des fonctions, la question est donc de savoir quelle est la différence entre les fonctions fléchées et les fonctions en ligne.

Une expression de fonction de flèche (également connue sous le nom de fonction de flèche) a une syntaxe plus courte par rapport aux expressions de fonction et ne lie pas la sienne this , arguments, superou new.target). Les fonctions fléchées sont toujours anonymes.

Quelques détails plus rapides ici


Pourquoi la fonction flèche ne peut pas être utilisée comme générateur

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

Utilisation du mot clé yield

Le mot-clé yield ne peut pas être utilisé dans le corps d'une fonction flèche (sauf lorsqu'il est autorisé dans les fonctions qui y sont imbriquées). Par conséquent, les fonctions fléchées ne peuvent pas être utilisées comme générateurs.

Notez que les générateurs sans yieldn'ont aucun sens.


Pourquoi la fonction flèche ne peut pas utiliser le rendement

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

Les fonctions fléchées se lient thislexicalement, se lient returndans le cas du corps de bloc afin qu'elles reviennent de la fonction fléchée immédiatement englobante, et empêchent breaket continuede référencer des instructions en dehors de la fonction fléchée immédiatement englobante.

L' expression principale de l' identifiantarguments ne peut pas être utilisée dans le corps d'une fonction flèche (que ce soit une expression ou une forme de bloc).

De même, yieldne peut pas être utilisé dans le corps d'une fonction flèche. Les flèches ne peuvent pas être génératrices et nous ne voulons pas de continuations profondes.

Le rendement dans une fonction fléchée générera une erreur sémantique: http://www.ecma-international.org/

En fin de compte, la raison réside dans la complexité profonde de la mise en œuvre d'ECMA6. C # ne le permet pas également pour des raisons quelque peu similaires .


3
J'ai utilisé un moteur de recherche et publié une autre explication pour vous
CoderPi

1
Je pense toujours que l'ajout d'explications sur ()=>{}aiderait beaucoup, pour comprendre sa différence par rapport à une fonction en ligne, et pourquoi la limitation est là pour les générateurs.
vitaly-t

63
J'essaie de comprendre pourquoi ça ne *() => { yield bla; }va pas, mais async () => { await bla; }est ...
Lee Benson

7
@CodeiSir, Re " et nous ne voulons pas de continuations profondes ", excuses pourries.
Pacerier

9
Votre argument est cyclique. Vous dites que les fonctions fléchées ne peuvent pas être génératrices car elles ne peuvent pas contenir le mot-clé yield. Mais ils ne peuvent pas avoir le mot-clé yield, car ils ne peuvent pas être des générateurs: "Les flèches ne peuvent pas être des générateurs et nous ne voulons pas de continuations profondes."
Thayne

36

Outre la discussion sur esdiscuss.org et les notes de réunion ES6 du comité Ecma TC39 de novembre 2013 mentionnées ci-dessus, les flèches du générateur ont été revues lors de deux réunions ES7 de septembre 2016 [1] [2] . Après une discussion sur les avantages et les inconvénients des différentes syntaxes (principalement=*> et =>*) et le manque de justifications et de cas d'utilisation pour cette fonctionnalité, ils sont arrivés à la conclusion que:

  • Il y a un certain intérêt de la part du comité, mais craignez que la fonctionnalité ne tire pas son poids pour l'ajout d'un nouveau morceau de syntaxe
  • Prévoyez de revoir le jour 3 pour voir si nous pouvons =>*au moins atteindre l'étape 0, dans le cadre de la proposition d'itération asynchrone de [Domenic Denicola]

La proposition de flèches de générateur a été déplacée à l' étape 1 avec Brendan Eich et Domenic Denicola comme champions. L'itération asynchrone mentionnée ci-dessus a été terminée et mise en œuvre en 2018.

En octobre 2019, un dépôt officiel de Sergey Rubanov est apparu avec plus de discussions sur la syntaxe et d'autres détails.


8

J'avais aussi la même question et je suis venu ici. Après avoir lu les articles et les commentaires, j'ai senti que l'utilisation du générateur dans une fonction de flèche semblait vague:

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

C'est peut-être la principale raison pour laquelle ils n'ont pas implémenté le générateur en relation avec la fonction flèche.


Mais, si j'étais l'un d'eux, j'aurais pu penser comme ceci:

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

Cela ressemble à la fonction asynchrone:

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

Parce que, avec une fonction normale, le mot-clé async existe, donc la fonction flèche l'utilise - async () =>semble probable async function().

Mais, il n'y a pas de mot-clé comme genou generatoret hélas la fonction de flèche ne l'utilise pas.

De conclure:

Même s'ils souhaitent implémenter le générateur dans la fonction flèche, je pense qu'ils doivent repenser la syntaxe du générateur dans le noyau js:

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

Et ce sera une grosse erreur. Donc, garder la fonction de flèche hors du générateur est plutôt cool.


Suite au commentaire @Bergi :

Non. Les fonctions fléchées sont supposées être légères (et n'ont pas de .prototype par exemple) et souvent monolignes, tandis que les générateurs sont à peu près l'inverse.

Je dirai que le but du générateur à utiliser est run-stop-run et donc je ne pense pas que nous devons nous soucier du prototype, du lexical, etc.


2
Pourrait également envisager des options exotiques, comme () ~> { yield 'a'; yield 'b'; }. Pour être honnête, j'adore les tildes.
Gershom

@Gershom C'est ainsi que les langages de programmation comme Perl se trompent totalement
Sapphire_Brick

2

Je sais que c'est très tard, mais une autre raison possible pourrait être la syntaxe. (*() => {})fonctionne peut-être , mais qu'en est-il (9 ** () => {})? Est-ce 9 à la puissance d'une fonction flèche, qui revient NaN, ou est-ce 9 fois la fonction flèche d'un générateur, qui revient également NaN? Cela pourrait être fait avec une syntaxe alternative, comme =>*mentionné par une autre réponse ici, mais peut-être qu'il y avait un désir de préserver la cohérence de la syntaxe de la fonction du générateur (par exemple. function* () {}Et { *genMethod() {} }) lors de sa mise en œuvre. Pas trop d'excuse, mais une raison.


1
: +1: pour les doubles astérisques ... Old school JS guy here. Qui a dit que vous ne pouviez pas apprendre de nouveaux trucs à un vieux chien: joie:
Shanimal

La seule raison pour laquelle ils ne le font pas, c'est parce que faire l'analyseur est difficile. C'est tout à fait possible et ne nécessite aucun compromis dans la syntaxe.
Jason McCarrell

@JasonMcCarrell S'ils se souciaient suffisamment de ne pas rendre l'analyseur trop complexe, Brendan Eich aurait peut-être dû mettre Scheme dans le navigateur.
Sapphire_Brick

1

Pour le moment, vous ne pouvez pas, mais à l'avenir, vous pourriez l'être parce que la proposition de publication de TC39 pour la même chose en octobre 2019, qui est à l'étape 1.


-4

Il y a une bonne solution de contournement avec redux-saga

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

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

4
Comment savons-nous qu'OP utilise Redux?
Maros
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.