Le traitement de chaque élément d'une collection est une opération très courante. JavaScript offre de nombreuses façons de parcourir une collection, des simples boucles for et for each aux compréhensions map(), filter() et tableau. Dans JavaScript 1.7, les itérateurs et les générateurs apportent de nouveaux mécanismes d'itération à la syntaxe JavaScript de base et fournissent également un mécanisme permettant de personnaliser le comportement des boucles for...in et for each.
Itérateur
Un itérateur est un objet qui accède à un élément d'une séquence de collection à la fois et garde une trace de la position actuelle de l'itération dans la séquence. En JavaScript, un itérateur est un objet qui fournit une méthode next() qui renvoie l'élément suivant de la séquence. Cette méthode lève une exception StopIteration lorsque tous les éléments de la séquence ont été parcourus.
Une fois qu'un objet itérateur est créé, il peut être appelé explicitement en appelant à plusieurs reprises next(), ou implicitement en utilisant les boucles for...in et for each de JavaScript.
Des itérateurs simples pour itérer sur des objets et des tableaux peuvent être créés à l'aide d'Iterator() :
Une fois l'initialisation terminée, la méthode next() peut être appelée pour accéder aux paires clé-valeur de l'objet dans l'ordre :
La boucle for…in peut être utilisée au lieu d’appeler explicitement la méthode next(). La boucle se termine automatiquement lorsque l'exception StopIteration est levée.
Si vous souhaitez uniquement itérer la valeur clé de l'objet, vous pouvez passer le deuxième paramètre à la fonction Iterator() avec la valeur true :
L'un des avantages de l'utilisation d'Iterator() pour accéder aux objets est que les propriétés personnalisées ajoutées à Object.prototype ne seront pas incluses dans l'objet séquence.
Iterator() peut également être utilisé sur des tableaux :
Tout comme pour parcourir un objet, passer true comme deuxième paramètre fera que le parcours sera l'index du tableau :
Utilisez le mot-clé let pour attribuer des index et des valeurs pour bloquer les variables à l'intérieur de la boucle, et vous pouvez également utiliser l'affectation de déstructuration :
Déclarer un itérateur personnalisé
Certains objets représentant une collection d'éléments doivent être itérés d'une manière spécifiée.
1. Itérer un objet représentant une plage doit renvoyer les nombres contenus dans la plage un par un
2. Les nœuds feuilles d'un arbre sont accessibles en utilisant la profondeur d'abord ou la largeur d'abord
3. L'itération sur un objet représentant les résultats d'une requête de base de données doit être renvoyée ligne par ligne, même si l'ensemble des résultats n'a pas encore été chargé dans un seul tableau
4. Un itérateur agissant sur une séquence mathématique infinie (comme la séquence de Fibonacci) doit renvoyer les résultats les uns après les autres sans créer de structure de données de longueur infinie
JavaScript vous permet d'écrire une logique d'itération personnalisée et de l'appliquer à un objet
Nous créons un simple objet Range contenant des valeurs basses et hautes :
Maintenant, nous créons un itérateur personnalisé qui renvoie une séquence contenant tous les entiers de la plage. L'interface de l'itérateur nous oblige à fournir une méthode next() pour renvoyer l'élément suivant de la séquence ou lever une exception StopIteration.
Notre RangeIterator est instancié avec une instance de plage et maintient une propriété actuelle pour suivre la position actuelle de la séquence.
Enfin, pour que RangeIterator soit combiné avec Range, nous devons ajouter une méthode __iterator__ spéciale pour Range. Il sera appelé lorsque nous essaierons de parcourir un Range et devra renvoyer une instance RangeIterator qui implémente la logique d'itération.
Une fois que nous avons terminé notre itérateur personnalisé, nous pouvons parcourir une instance de plage :
Générateurs : une meilleure façon de créer des itérateurs
Bien que les itérateurs personnalisés soient un outil utile, une planification minutieuse est nécessaire lors de leur création car leur état interne doit être maintenu explicitement.
Le générateur fournit des fonctions très puissantes : il vous permet de définir une fonction qui contient son propre algorithme d'itération, et il peut automatiquement maintenir son propre état.
Les générateurs sont des fonctions spéciales qui peuvent servir d'usines d'itérateurs. Si une fonction contient une ou plusieurs expressions de rendement, elle est appelée générateur (Note du traducteur : Node.js doit également ajouter * devant le nom de la fonction pour l'indiquer).
Remarque : seuls les blocs de code contenus dans