Itérable
Les objets itérables sont des objets que l'on peut parcourir par une boucle for...of. Par exemple les tableaux et les chaînes de caractères :
for(let elt of [3,4,5]) console.log(elt); // affiche 3, 4 et 5
for(let elt of "abc") console.log(elt); // affiche "a", "b" et "c"
Il est possible de rendre n'importe quel objet itérable à condition qu'il implémente la méthode @@iterator via la propriété [Symbol.iterator].
Cette propriété devra retourner un itérateur.
const iterable = {
[Symbol.iterator] : function(){ return //un iterateur }
}
Définition : Itérateur
Un itérateur est un objet qui implémente la méthode next(). Cette méthode retourne un objet qui contient les propriétés value et done.
let i = 0;
const iterateur = {
next: function () {
if (i < 3) {
return { value: i++, done: false }
} else {
return { value: undefined, done: true }
}
}
}
console.log(iterateur.next()); // {value: 0, done: false}
console.log(iterateur.next()); // {value: 1, done: false}
console.log(iterateur.next()); // {value: 2, done: false}
console.log(iterateur.next()); // {value: undefined, done: true}
console.log(iterateur.next()); // {value: undefined, done: true}
Ajoutons notre itérateur à la propriété [Symbol.iterator] de notre objet itérable .
La boucle for...of retourne les valeurs de notre itérateur :
const iterable = {
[Symbol.iterator]: function () {
let i = 0;
return {
next: function () {
if (i < 3) {
return { value: i++, done: false }
} else {
return { value: undefined, done: true }
}
}
}
}
}
for(let elt of iterable) console.log(elt); // affiche 0, 1, et 2
La boucle lance la méthode [Symbol.iterator] tant que l'itérateur retourne un objet dont la propriété done vaut false.
Exemple : Générateur
Une fonction génératrice permet de générer des itérateurs.
On ajoute le symbole * après le mot clé function.
const generateur = function* () {
yield 0;
yield 1;
yield 2;
}
const iterateur = generateur();
console.log(iterateur.next()); // {value: 0, done: false}
console.log(iterateur.next()); // {value: 1, done: false}
console.log(iterateur.next()); // {value: 2, done: false}
console.log(iterateur.next()); // {value: undefined, done: true}
console.log(iterateur.next()); // {value: undefined, done: true}
Au premier appel de la méthode next sur l'iterateur le corps de la fonction generateur est utilisé jusqu'au premier mot clé yield qui agit comme un return.
Aux appels suivants de next l'utilisation du corps de la fonction generateur redémarre à l'endroit ou elle s'était arrétée et s’arrête au prochain yield.
Lorsqu'il n'y a plus de yield, l'iterateur retournera un objet {value: undefined, done : false}.
Le générateur peut être paramétré :
const generateur = function* (n) {
let i = 0;
while (i < n) yield i++;
}
const iterateur = generateur(3);
console.log(iterateur.next()); // {value: 0, done: false}
console.log(iterateur.next()); // {value: 1, done: false}
console.log(iterateur.next()); // {value: 2, done: false}
console.log(iterateur.next()); // {value: undefined, done: true}
console.log(iterateur.next()); // {value: undefined, done: true}
Ce qui donne pour notre itérable :
const iterable = {
[Symbol.iterator]: function* () {
let i = 0;
while (i < 3) yield i++;
}
}
for(let elt of iterable) console.log(elt); // affiche 0, 1, et 2
Exemple : Exemple d'objet Liste
Construisons un objet liste itérable sur ses propriétés numériques
const liste = {
[Symbol.iterator]: function*() {
let i = 0;
while (this[i]) {
yield this[i++];
}
}
}
liste[0] = 3;
liste[1] = 7;
liste[2] = 2;
for(let elt of liste) console.log(elt); // affiche 3, 7 et 2
tant que des indices numériques existent à partir de 0 sans discontinuer, l'itérateur retourne une valeur.
Utilisation avec une class :
class Liste {
constructor(tab) { // la liste des paramètres est stockée dans le tableau tab
let i=0;
for (let elt of tab) this[i++] = elt; // pour chaque valeur du tableau
} // une propriété numérique (i) est générée
// qui contient la valeur
*[Symbol.iterator]() {
let i = 0;
while (this[i]) {
yield this[i++];
}
}
}
const liste = new Liste(3,7,2); // liste[0], liste[1], liste[2] sont générée
for(let elt of liste) console.log(elt); // affiche 3, 7 et 2
*[Symbol.iterator]() est la contraction de [Symbol.iterator] = function*()