L'itération fait référence au processus d'extraction continue de données d'un ensemble de données dans un certain ordre.
Alors, quelle est la différence entre itération et parcours ?
En JavaScript, un itérateur est un objet qui peut appeler next
pour implémenter cette méthode. renvoie un objet An avec deux propriétés.
value
: La valeur suivante de l'objet itérabledone
: Indique si toutes les données ont été récupérées. false
signifie qu'il y a encore des données, true
signifie qu'il n'y a plus de données plus tard.pour générer des itérateurs via la fonction de fabrique d'itérateurs Symbol.iterator
dans l'objet itérable.
const arr = []console.log(arr)
constarr = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // Génère un itérateur via la fonction de fabrique d'itérateurs `Symbol.iterator`. console.log(iter1) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log('%c%s', 'color:red;font-size:24px;', '================') const ma carte = nouvelle carte () macarte.set('nom', 'clz') ma carte.set('âge', 21) const iter2 = mymap[Symbol.iterator]() // Génère un itérateur via la fonction de fabrique d'itérateurs `Symbol.iterator`. console.log(iter2) console.log(iter2.next()) console.log(iter2.next()) console.log(iter2.next())
On peut constater que l'itérateur est terminé après avoir pris la dernière valeur, c'est-à-dire lorsque la value
suivante de l'itérateur n'est undefined
.
Mais l'instruction ci - dessus n'est pas très précise. Elle n'est pas terminée lorsque la value
suivante de l'itérateur est undefined
. Vous devez également déterminer s'il n'y a vraiment aucune valeur ou s'il existe une valeur dans l'objet itérable qui undefined
. S'il y a une valeur dans l'objet itérable qui undefined
, elle ne sera pas terminée pour le moment.
const arr = [1, 2, 3, non défini] const iter1 = arr[Symbol.iterator]() // Génère un itérateur via la fonction de fabrique d'itérateurs `Symbol.iterator`. console.log(iter1) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next())
peuvent appeler la fonction de fabrique d'itérateurs plusieurs fois sans interférer les uns avec les autres pour générer plusieurs itérateurs. Chaque itérateur représente un parcours ordonné unique de l'objet itérable. Différents itérateurs n'interfèrent pas les uns avec les autres et ne parcourront que les objets itérables indépendamment .
constarr = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // Génère un itérateur via la fonction de fabrique d'itérateurs `Symbol.iterator`. const iter2 = arr[Symbol.iterator]() console.log('Itérateur1:', iter1.next()) console.log('Itérateur2:', iter2.next()) console.log('Itérateur1:', iter1.next()) console.log('Itérateur2:', iter2.next())
const arr = [1, 2, 3] const iter = arr[Symbol.iterator]() pour (const i de iter) { console.log(i) // Sortie 1, 2, 3 en séquence }
Si l'objet itérable est modifié au cours de l'itération, le résultat obtenu par l'itérateur sera également modifié.
constarr = [1, 2, 3] console.log(arr) const iter = arr[Symbol.iterator]() console.log(iter.next()) arrêt[1] = 999 console.log(iter.next()) console.log(iter.next())
Lorsque nous itérons jusqu'à done: true
, une erreur sera-t-elle signalée lors de l'appel next
, ou rien ne sera renvoyé ?
Cependant, non, l'itérateur sera dans un état terminé mais pas terminé . done: true
signifie qu'il a été terminé, mais next
peut toujours être appelé à l'avenir, même si le résultat sera toujours { value: undefined, done: true }
. C'est pourquoi on dit que c'est fait mais pas fait .
constarr = [1, 2, 3] const iter = arr[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())
À partir de l'exemple ci-dessus, nous pouvons savoir que l'itérateur est généré via la fonction d'usine d'itérateur Symbol.iterator
, nous devons donc implémenter une fonction d'usine d'itérateur d'itérateur, puis l'itérateur peut appeler la méthode next
, vous devez donc également implémentez une méthode next
. Quant à la fonction de fabrique d'itérateurs, elle renvoie en fait l'instance this
directement.
Exemple de compteur :
classe Compteur { constructeur (limite) { ceci.count = 1 this.limit = limite } suivant() { si (this.count <= this.limit) { retour { fait : faux, valeur : this.count++ } } autre { return { done : true, valeur : non définie } } } [Symbol.iterator]() { rends ceci }}
compteur const = nouveau compteur (3) const iter = compteur[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())
À première vue, il n'y a pas de problème, mais si nous utilisons for-of
pour parcourir, nous pouvons trouver le problème.
const counter = new Counter(3)for (soit i du compteur) { console.log(i)}console.log('Une autre itération :')for (laissez i du compteur) { console.log(i)}
L'utilisation for-of
la rend également jetable. En effet, count
est une variable de cette instance, donc la même variable est utilisée dans les deux itérations. Cependant, après la première boucle de la variable, elle a dépassé la limite, vous n'obtiendrez donc rien en utilisant for-of
. encore une fois. Le résultat était.
Vous pouvez mettre la variable count
dans une fermeture, puis renvoyer l'itérateur via la fermeture, afin que chaque itérateur créé corresponde à un nouveau compteur.
compteur de classe { constructeur (limite) { this.limit = limite } [Symbol.iterator]() { laissez compter = 1 const limite = this.limit return { // La fonction de fabrique d'itérateurs doit renvoyer un objet avec une méthode next, car l'itération est en fait implémentée en appelant la méthode next next() { si (nombre <= limite) { retour { fait : faux, valeur : compte++ } } autre { return { done : true, valeur : non définie } } } } }}
Test
const counter = new Counter(3)for (soit i du compteur) { console.log(i)}console.log('Une autre itération :')for (laissez i du compteur) { console.log(i)}
revient à utiliser for-of
. L'itérateur appellera intelligemment next
. Lorsque l'itérateur se terminera plus tôt, il appellera également la méthode return
.
[Symbol.iterator]() { laissez compter = 1 const limite = this.limit return { // La fonction de fabrique d'itérateurs doit renvoyer un objet avec une méthode next, car l'itération est en fait implémentée en appelant la méthode next next() { si (nombre <= limite) { retour { fait : faux, valeur : compte++ } } autre { return { done : true, valeur : non définie } } }, retour() { console.log('Terminaison anticipée de l'itérateur') retourner { terminé : vrai } } }}
Test
const counter = new Counter(5)for (soit i du compteur) { si (je === 3) { casser; } console.log(i)}
Si l'itérateur n'est pas fermé, vous pouvez continuer l'itération là où vous vous étiez arrêté . Les itérateurs de tableau ne peuvent pas être fermés.
const arr = [1, 2, 3, 4, 5]const iter = arr[Symbol.iterator]()iter.return = function () { console.log('Quitter l'itérateur plus tôt') retour { fait : vrai }}pour (const i de iter) { console.log(i) si (je === 2) { casser }}pour (const i de iter) { console.log(i)}