Maîtrisez les protocoles qui alimentent for...of, le spread et la déstructuration, puis exploitez les générateurs pour produire des séquences paresseuses.
Ouvrir cette leçon dans KodokonDeux protocoles distincts régissent l'itération. Un objet est itérable s'il expose une méthode sous la clé Symbol.iterator ; cette méthode doit renvoyer un itérateur, c'est-à-dire un objet doté d'une méthode next() retournant { value, done }. Tout ce qui consomme des séquences - for...of, le spread ..., la déstructuration, Array.from, Promise.all - passe par ces protocoles. Vous pouvez donc rendre n'importe quel objet compatible.
const range = {
from: 1,
to: 3,
[Symbol.iterator]() {
let current = this.from;
const last = this.to;
return {
next() {
return current <= last
? { value: current++, done: false }
: { value: undefined, done: true };
}
};
}
};
console.log([...range]); // [1, 2, 3]Écrire des itérateurs à la main est verbeux. Les générateurs (function*) produisent un itérateur automatiquement : chaque yield suspend l'exécution et conserve l'état local de la fonction. Cette évaluation paresseuse permet de modéliser des séquences infinies, tant qu'un consommateur limite le nombre de valeurs demandées.
function* naturals() {
let n = 0;
while (true) yield n++;
}
function* take(iterable, count) {
let index = 0;
for (const value of iterable) {
if (index >= count) return;
yield value;
index += 1;
}
}
console.log([...take(naturals(), 4)]); // [0, 1, 2, 3]Les itérateurs de générateur exposent aussi return() et throw(). Point de spécification souvent ignoré : quand vous quittez une boucle for...of avec break, return ou une exception, le moteur appelle automatiquement iterator.return(). Dans un générateur, cela exécute les blocs finally en attente - l'endroit idéal pour libérer une ressource (fichier, connexion, verrou).
function* readLines() {
try {
yield "line 1";
yield "line 2";
} finally {
console.log("cleanup");
}
}
for (const line of readLines()) {
console.log(line);
break; // declenche return(), donc le finally
}
// line 1, cleanuplength et des index numériquesSymbol.iterator qui renvoie un objet doté de next()Array.prototypenext()for...of avec break alors qu'elle consomme un générateur ?throw() sur l'itérateurreturn(), ce qui exécute les blocs finally du générateurnext()