2 votes

Générateurs Javascript ES6. Que sont-ils exactement ?

Je vois donc le lien ci-dessous et je me demande : à quoi cela sert-il exactement ? Qu'est-ce que cela accomplit réellement et dans quel but ?

L'exemple est peut-être un peu trop compliqué pour un débutant comme moi, mais honnêtement, je ne comprends pas.

http://es6-features.org/#GeneratorFunctionIteratorProtocol

Exemple tiré de la source ci-dessus :

let fibonacci = { * [Symbol.iterator]() {
        let pre = 0,
            cur = 1
        for (;;) {
            [pre, cur] = [cur, pre + cur] yield cur
        }
    }
}
for (let n of fibonacci) {
    if (n > 1000) break console.log(n)
}

4voto

nnnnnn Points 70578

La grande question est cependant : à quoi sert-il ?

Certains objets ont une méthode d'itération naturelle et évidente, par exemple avec un tableau ou une chaîne de caractères, vous pouvez accéder à chaque élément ou caractère dans l'ordre en utilisant son index. Mais d'autres objets sont plus compliqués, et JavaScript ne peut pas deviner comment vous pourriez vouloir itérer à travers leurs propriétés. En implémentant le protocole d'itération sur un objet, vous pouvez définir votre propre comportement d'itération sur les objets suivants cualquier mais de manière à ce que d'autres codes puissent y accéder en utilisant des méthodes standard. for of ou en utilisant l'itérateur .next() méthode . Vous pouvez même définir plus d'une méthode d'itération afin de pouvoir itérer sur le même objet dans différentes séquences. Ou, comme dans votre exemple, vous pouvez implémenter un objet qui n'itère pas sur ses propres propriétés, mais qui génère une liste infinie de valeurs, mais une par une lorsqu'on lui demande la suivante.

Prenons donc un peu de recul et examinons une structure plus courante, comme un tableau de valeurs de longueur fixe :

var colours = ["Red", "Yellow", "Green", "Brown", "Blue"];

La vieille méthode pour faire quelque chose avec toutes les valeurs est un simple for boucle :

for (var i = 0; i < colours.length; i++)
  console.log(colours[i]);

Mais la nouvelle alternative for of vous permet d'obtenir le même effet sans avoir à vous soucier de l'initialisation et de l'incrémentation de l'élément i ou en testant la longueur du tableau :

for (let colour of colours)
   console.log(colour);

Donc, pour en revenir à votre fibonacci Par exemple, la séquence de Fibonacci est infinie, mais il est impossible de créer un tableau de longueur infinie, de le remplir d'une liste infinie de valeurs, puis d'effectuer une itération sur ce tableau. Mais en utilisant les générateurs ES6, vous pouvez créer un tableau fibonacci sur lequel vous pouvez itérer presque comme s'il s'agissait d'un tableau :

for (let n of fibonacci) {
    if (n > 1000) break;
    console.log(n)
}

La boucle ne se soucie pas de savoir comment fibonacci est implémenté, tout ce qu'il sait est qu'il s'agit d'un objet itérable. La boucle peut le traiter comme une liste générique, en notant que parce qu'il se comporte comme une liste de longueur infinie, la boucle a besoin de la fonction if y break de sorte qu'il s'arrête à la limite qui semble appropriée. Si la liste était finie, vous n'auriez pas besoin de ça. if la boucle se termine naturellement après le traitement du dernier élément.

Donc, en regardant maintenant la mise en œuvre de fibonacci vous remarquerez qu'il contient ce qui ressemble à une boucle infinie :

for (;;) {...}

C'est la vieille école for syntaxe, mais sans condition de fin, donc ça continue à l'infini. Sauf qu'à l'intérieur de la boucle, vous avez un yield déclaration :

    yield cur

...qui renvoie la valeur cur mais contrairement à l'utilisation d'un return dans une fonction, il ne termine pas la fonction, il ne fait que la "mettre en pause", contrôle des rendements de retourner au code en utilisant l'itérateur, mais en gardant toutes les variables à jour et prêtes à être utilisées plus tard lorsqu'on lui demandera la valeur suivante. Si votre autre code ne demande jamais la valeur suivante, ce n'est pas grave, car vous n'avez pas occupé une tonne de mémoire en gardant la trace de tous les nombres de la séquence jusqu'à présent - il n'est pas nécessaire de calculer la séquence à l'avance, le code a seulement besoin de savoir quelles sont les valeurs actuelles et précédentes afin de calculer la valeur suivante.

Bien sûr, même avant ES6, vous pouviez implémenter une sorte de méthode d'itération sur vos objets, avec une fonction qui conserve l'état d'une manière ou d'une autre, de sorte qu'à chaque appel suivant, elle continue là où elle s'est arrêtée. Ce n'est pas difficile, mais alors le code qui utilise cet objet doit savoir si la méthode est appelée .next() ou getNext() ou autre, et vous devrez appeler cette méthode explicitement et gérer votre propre boucle. Le nouveau concept de générateur ES6 vous permet d'implémenter ces choses d'une manière standard et transparente pour le code appelant, de sorte que vous pouvez simplement les brancher dans un simple fichier for of boucle.

Le sujet est complexe et il existe d'autres utilisations (comme l'asynchronisme mentionné dans l'autre réponse), mais j'espère que cela vous a aidé un peu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X