JavaScript pour tout le monde : itérateurs —

Hé, je m’appelle Mat, mais « Wilto » fonctionne aussi : je suis ici pour vous apprendre JavaScript. Eh bien, non ici-ici; techniquement, j’en suis à Piccalil.li’s JavaScript pour tous cours pour vous apprendre JavaScript. Ce qui suit est un extrait du Itérables et itérateurs module : la leçon sur les itérateurs.
Les itérateurs sont l’un des sujets JavaScript les plus déroutants sur le plan linguistique. facilement au-dessus de ce qui est déjà une barre assez haute. Il y a itérables – tableau, ensemble, carte et chaîne – qui suivent tous le protocole itérable. Pour suivre ledit protocole, un objet doit implémenter le interface itérable. En pratique, cela signifie que l’objet doit inclure un [Symbol.iterator]() méthode quelque part dans sa chaîne de prototypes. Le protocole itérable est l’un des deux protocoles d’itération. L’autre protocole d’itération est le protocole d’itérateur.
Vous voyez ce que je veux dire par le fait que cela soit linguistiquement lourd ? Les itérables implémentent l’interface d’itération itérable, et les itérateurs implémentent l’interface d’itération itérateur ! Si vous pouvez dire cela cinq fois plus vite, alors vous avez à peu près compris l’essentiel ; facile, non ?
Non, écoutez, au moment où vous atteindrez la fin de cette leçon, je vous promets que ce ne sera pas aussi déroutant que cela puisse paraître, surtout avec le contexte que vous aurez des leçons qui la précèdent.
Un itérable L’objet suit le protocole itérable, ce qui signifie simplement que l’objet dispose d’une méthode conventionnelle pour créer des itérateurs. Les éléments qu’il contient peuvent être bouclés avec for…of.
Un itérateur l’objet suit le protocole de l’itérateur et les éléments qu’il contient sont accessibles séquentiellementun à la fois.
À réitérer — un jeu de mots pour lequel je ne me pardonne pas et que je n’attends pas de vous que vous me pardonniez — un itérateur l’objet suit le protocole de l’itérateur et les éléments qu’il contient sont accessibles séquentiellementun à la fois. Le protocole Iterator définit une manière standard de produire une séquence de valeurs, et éventuellement return une valeur une fois que toutes les valeurs possibles ont été générées.
Afin de suivre le protocole de l’itérateur, un objet doit – vous l’aurez deviné – implémenter le interface de l’itérateur. En pratique, cela signifie encore une fois qu’une certaine méthode doit être disponible quelque part dans la chaîne de prototypes de l’objet. Dans ce cas, c’est le next() méthode qui avance à travers les éléments qu’elle contient, un à la fois, et renvoie un objet à chaque fois que cette méthode est appelée.
Afin de répondre aux critères de l’interface de l’itérateur, l’objet renvoyé doit contenir deux propriétés avec des clés spécifiques : une avec la clé valuereprésentant la valeur de l’élément actuel, et un avec la clé doneune valeur booléenne qui nous indique si l’itérateur a avancé au-delà de l’élément final de la structure de données. Ce n’est pas une formulation gênante que l’équipe éditoriale a laissée passer : la valeur de cela done la propriété est true seulement lorsqu’un appel à next() entraîne une tentative d’accès à un élément au-delà l’élément final de l’itérateur, et non lors de l’accès à l’élément final de l’itérateur. Encore une fois, il y a beaucoup de choses sous forme imprimée, mais cela aura plus de sens lorsque vous le verrez en action.
Vous avez déjà vu un exemple d’itérateur intégré, quoique brièvement :
const theMap = new Map([ [ "aKey", "A value." ] ]);
console.log( theMap.keys() );
// Result: Map Iterator { constructor: Iterator() }
C’est vrai : alors qu’un objet Map lui-même est un itérable, les méthodes intégrées de Map keys(), values()et entries() tous renvoient des objets Iterator. Vous vous souviendrez également que j’ai parcouru ceux qui utilisaient forEach (un ajout relativement récent à la langue). Utilisé de cette façon, un itérateur ne se distingue pas d’un itérable :
const theMap = new Map([ [ "key", "value " ] ]);
theMap.keys().forEach( thing => {
console.log( thing );
});
// Result: key
Tous les itérateurs sont itérables ; ils implémentent tous l’interface itérable :
const theMap = new Map([ [ "key", "value " ] ]);
theMap.keys()[ Symbol.iterator ];
// Result: function Symbol.iterator()
Et si vous êtes en colère contre le flou croissant de la frontière entre les itérateurs et les itérables, attendez d’avoir accès à cette vidéo candidate des « dix principales trahisons d’anime » : je vais vous montrer comment interagir avec un itérateur en utilisant un tableau.
« BOO », pleurez-vous sûrement, après avoir été tellement trahi par l’un de vos amis les plus anciens et les plus répertoriés. « Le tableau est un itérablepas une itèretor! » Vous avez tous les deux raison de me crier dessus en général, et vous avez raison à propos du tableau en particulier : un tableau est un itérable, pas un itérateur. En fait, même si tous les itérateurs sont itérables, aucun des itérables intégrés n’est un itérateur.
Cependant, quand tu appelles ça [ Symbol.iterator ]() méthode – celle qui définit un objet comme itérable – elle renvoie un objet itérateur créé à partir d’une structure de données itérable :
const theIterable = [ true, false ];
const theIterator = theIterable[ Symbol.iterator ]();
theIterable;
// Result: Array [ true, false ]
theIterator;
// Result: Array Iterator { constructor: Iterator() }
Il en va de même pour Set, Map et, oui, même les chaînes :
const theIterable = "A string."
const theIterator = theIterable[ Symbol.iterator ]();
theIterator;
// Result: String Iterator { constructor: Iterator() }
Ce que nous faisons ici manuellement : créer un itérateur à partir d’un itérable en utilisant %Symbol.iterator% – c’est précisément comment les objets itérables fonctionnent en interne et pourquoi ils doivent implémenter %Symbol.iterator% pour être itérables. Chaque fois que vous parcourez un tableau, vous parcourez en fait un itérateur créé à partir de ce tableau. Tous les itérateurs intégrés sont itérable. Tous les itérables intégrés peuvent être utilisés pour créer itérateurs.
Alternativement – de préférencemême, puisqu’il ne nécessite pas de frôler %Symbol.iterator% directement – vous pouvez utiliser le Iterator.from() méthode pour créer un objet itérateur à partir de n’importe quel itérable :
const theIterator = Iterator.from([ true, false ]);
theIterator;
// Result: Array Iterator { constructor: Iterator() }
Vous vous souvenez de la façon dont j’ai mentionné qu’un itérateur doit fournir un next() méthode (qui renvoie un objet très spécifique) ? Appeler ça next() La méthode parcourt les éléments que l’itérateur contient un par un, chaque appel renvoyant une instance de cet objet :
const theIterator = Iterator.from([ 1, 2, 3 ]);
theIterator.next();
// Result: Object { value: 1, done: false }
theIterator.next();
// Result: Object { value: 2, done: false }
theIterator.next();
// Result: Object { value: 3, done: false }
theIterator.next();
// Result: Object { value: undefined, done: true }
Vous pouvez considérer cela comme une forme de parcours plus contrôlée que le traditionnel « enroulez-le et regardez-le partir » for boucles auxquelles vous êtes probablement habitué – une méthode permettant d’accéder aux éléments une étape à la fois, selon les besoins. Certes, tu ne le fais pas avoir parcourir un itérateur de cette manière, puisqu’ils ont leur propre Iterator.forEach méthode, qui fonctionne exactement comme vous vous en doutez — jusqu’à un certain point :
const theIterator = Iterator.from([ true, false ]);
theIterator.forEach( element => console.log( element ) );
/* Result:
true
false
*/
Mais il y a une autre grande différence entre les itérables et les itérateurs que nous n’avons pas encore abordée, et pour mon argent, cela contribue grandement à rendre linguistique sens des deux. Cependant, vous devrez peut-être me faire plaisir un peu ici.
Vous voyez, un objet itérable est un objet itérable. Non, écoutez, restez avec moi : vous pouvez parcourir un tableau, et lorsque vous avez terminé, vous pouvez toujours parcourir ce tableau. Il s’agit, par définition, d’un objet sur lequel on peut effectuer une itération ; c’est la nature essentielle d’un itérable d’être itérable :
const theIterable = [ 1, 2 ];
theIterable.forEach( el => {
console.log( el );
});
/* Result:
1
2
*/
theIterable.forEach( el => {
console.log( el );
});
/* Result:
1
2
*/
D’une certaine manière, un objet itérateur représente le singulier acte d’itération. Interne à un itérable, c’est le mécanisme par lequel l’itérable est itéré, à chaque fois que cette itération est effectuée. En tant qu’objet itérateur autonome — que vous le parcouriez à l’aide de l’option next méthode ou boucle sur ses éléments en utilisant forEach – une fois itéré, cet itérateur est passé; c’est itératif. Parce qu’ils maintiennent un état interne, la nature essentielle d’un itérateur est d’être itéré, au singulier :
const theIterator = Iterator.from([ 1, 2 ]);
theIterator.next();
// Result: Object { value: 1, done: false }
theIterator.next();
// Result: Object { value: 2, done: false }
theIterator.next();
// Result: Object { value: undefined, done: true }
theIterator.forEach( el => console.log( el ) );
// Result: undefined
Cela permet un travail soigné lorsque vous utilisez les méthodes intégrées du constructeur Iterator pour, par exemple, filtrer ou extraire une partie d’un objet Iterator :
const theIterator = Iterator.from([ "First", "Second", "Third" ]);
// Take the first two values from `theIterator`:
theIterator.take( 2 ).forEach( el => {
console.log( el );
});
/* Result:
"First"
"Second"
*/
// theIterator now only contains anything left over after the above operation is complete:
theIterator.next();
// Result: Object { value: "Third", done: false }
Une fois que vous atteignez la fin d’un itérateur, l’action d’itérer dessus est terminée. Itératif. Passé.
Et votre temps passé dans cette leçon l’est également, vous pourriez être soulagé de l’entendre. Je sais que c’était un peu difficile, mais la bonne nouvelle est la suivante : ce cours est itérable, pas itérateur. Cette étape de votre itération – cette leçon – est peut-être terminée, mais la nature essentielle de ce cours est que vous pouvez le parcourir à nouveau. Ne vous inquiétez pas de mémoriser tout cela pour le moment : vous pouvez revenir et revoir cette leçon à tout moment.
Conclusion
Je maintiens ce que j’ai écrit là-bas, aussi surprenant que cela puisse paraître : cette leçon est délicate, mais écoutez, tu as ça. JavaScript pour tous est conçu pour vous emmener dans la tête de JavaScript. Une fois que vous avez commencé à voir comment les engrenages s’emboîtent – vu les empreintes digitales laissées par les personnes qui ont construit le langage, et les bonnes, mauvaises et parfois déroutantes décisions qui ont conduit à cela – non cause-si -ble ou -tor pourra se mettre en travers de votre chemin.

Mon objectif est de vous apprendre le magie profonde – le comment et le pourquoi de JavaScript, en utilisant les syntaxes que vous êtes le plus susceptible de rencontrer dans votre travail quotidien, à votre rythme et selon vos conditions. Si vous débutez dans ce langage, vous repartirez de ce cours avec une compréhension fondamentale de JavaScript valant des centaines d’heures d’essais et d’erreurs. Si vous êtes un développeur junior, vous terminerez ce cours avec des connaissances approfondies qui rivaliseront avec n’importe quel senior.
J’espère vous y voir.
(gg, ouais)
Source link
