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 :

CTRL+C pour copier, CTRL+V pour coller
1
for(let elt of [3,4,5]) console.log(elt);  // affiche 3, 4 et 5
2
for(let elt of "abc") console.log(elt);  // affiche "a", "b" et "c"
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.

CTRL+C pour copier, CTRL+V pour coller
1
const iterable = {
2
    [Symbol.iterator] : function(){ return //un iterateur }
3
}
const iterable = {
    [Symbol.iterator] : function(){ return //un iterateur }
}

DéfinitionIté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.

CTRL+C pour copier, CTRL+V pour coller
1
let i = 0;
2
const iterateur = {
3
    next: function () {
4
        if (i < 3) {
5
            return { value: i++, done: false }
6
        } else {
7
            return { value: undefined, done: true }
8
        }
9
    }
10
}
11
console.log(iterateur.next());  // {value: 0, done: false}
12
console.log(iterateur.next());  // {value: 1, done: false}
13
console.log(iterateur.next());  // {value: 2, done: false}
14
console.log(iterateur.next());  // {value: undefined, done: true}
15
console.log(iterateur.next());  // {value: undefined, done: true}
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 :

CTRL+C pour copier, CTRL+V pour coller
1
const iterable = {
2
    [Symbol.iterator]: function () {
3
        let i = 0;
4
        return {
5
            next: function () {
6
                if (i < 3) {
7
                    return { value: i++, done: false }
8
                } else {
9
                    return { value: undefined, done: true }
10
                }
11
            }
12
        }
13
    }
14
}
15
for(let elt of iterable) console.log(elt); // affiche 0, 1, et 2
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.

ExempleGé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.

CTRL+C pour copier, CTRL+V pour coller
1
const generateur = function* () {
2
    yield 0;
3
    yield 1;
4
    yield 2;
5
}
6
const iterateur = generateur();
7
console.log(iterateur.next()); // {value: 0, done: false}
8
console.log(iterateur.next()); // {value: 1, done: false}
9
console.log(iterateur.next()); // {value: 2, done: false}
10
console.log(iterateur.next()); // {value: undefined, done: true}
11
console.log(iterateur.next()); // {value: undefined, done: true}
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é :

CTRL+C pour copier, CTRL+V pour coller
1
const generateur = function* (n) {
2
    let i = 0;
3
    while (i < n) yield i++;
4
}
5
const iterateur = generateur(3);
6
console.log(iterateur.next()); // {value: 0, done: false}
7
console.log(iterateur.next()); // {value: 1, done: false}
8
console.log(iterateur.next()); // {value: 2, done: false}
9
console.log(iterateur.next()); // {value: undefined, done: true}
10
console.log(iterateur.next()); // {value: undefined, done: true}
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 :

CTRL+C pour copier, CTRL+V pour coller
1
const iterable = {
2
    [Symbol.iterator]: function* () {
3
        let i = 0;
4
        while (i < 3) yield i++;
5
    }
6
}
7
for(let elt of iterable) console.log(elt); // affiche 0, 1, et 2
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

ExempleExemple d'objet Liste

Construisons un objet liste itérable sur ses propriétés numériques

CTRL+C pour copier, CTRL+V pour coller
1
const liste = {
2
    [Symbol.iterator]: function*() {
3
        let i = 0;
4
        while (this[i]) {
5
            yield this[i++];
6
        }
7
    }
8
}
9
10
liste[0] = 3;
11
liste[1] = 7;
12
liste[2] = 2;
13
for(let elt of liste) console.log(elt); // affiche 3, 7 et 2
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 :

CTRL+C pour copier, CTRL+V pour coller
1
class Liste {
2
3
    constructor(...tab) {                        // la liste des paramètres est stockée dans le tableau tab
4
        let i=0;
5
        for (let elt of tab) this[i++] = elt;    // pour chaque valeur du tableau
6
    }                                            // une propriété numérique (i) est générée
7
                                                 // qui contient la valeur
8
    *[Symbol.iterator]() {
9
        let i = 0;
10
        while (this[i]) {
11
            yield this[i++];
12
        }
13
    }
14
}
15
16
const liste = new Liste(3,7,2);                  // liste[0], liste[1], liste[2] sont générée 
17
for(let elt of liste) console.log(elt);          // affiche 3, 7 et 2 
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*()