for...of
========

L'**instruction `for...of`** permet de créer une boucle `Array` qui parcourt un objet itérable (ce qui inclut les objets `Array`, `Map`, `Set`, `String`, `TypedArray`, l'objet `arguments`, etc.) et qui permet d'exécuter une ou plusieurs instructions pour la valeur de chaque propriété.

Exemple interactif
------------------

Syntaxe
-------


```js
for (variable of iterable) {
  instruction;
}
```


`variable`

À chaque itération, la valeur d'une propriété différente est affectée à `variable` (cette variable peut être déclarée avec `const`, `let` ou `var`).

`iterable`

L'objet dont on parcourt les propriétés énumérables.

`instruction`

Une instruction à exécuter pour chaque propriété, cette instruction peut être composée de plusieurs instructions en utilisant un bloc d'instructions.

Exemples
--------

### Utiliser `for...of` sur un tableau


```js
let tableauItérable = [1, 2, 3];

for (let valeur of tableauItérable) {
  console.log(valeur);
}
// 1
// 2
// 3
```


Si la variable n'est pas réaffectée dans la boucle, on pourra également utiliser `const` à la place de `let` :


```js
let tableauItérable = [1, 2, 3];

for (const valeur of tableauItérable) {
  console.log(valeur);
}
// 1
// 2
// 3
```

### Parcourir une chaîne de caractères avec `for...of`


```js
let iterable = "pixel";

for (let valeur of iterable) {
  console.log(valeur);
}
// p
// i
// x
// e
// l
```

### Parcourir un tableau typé (`TypedArray`)


```js
let iterable = new Uint8Array([0x00, 0xff]);

for (let valeur of iterable) {
  console.log(valeur);
}
// 0
// 255
```

### Parcourir une `Map`


```js
let iterable = new Map([
  ["a", 1],
  ["b", 2],
  ["c", 3],
]);

for (let element of iterable) {
  console.log(element);
}
// ['a', 1]
// ['b', 2]
// ['c', 3]

for (let [clef, valeur] of iterable) {
  console.log(valeur);
}
// 1
// 2
// 3
```

### Utiliser `Array.prototype.forEach()`

Pour obtenir les mêmes valeurs qu'avec une boucle `for...of`, on peut utiliser la méthode `Array.prototype.forEach()` :


```js
let arr = [3, 5, 7];
arr.toto = "coucou";

arr.forEach(function (element, index) {
  console.log(element); // affiche "3", "5", "7"
  console.log(index); // affiche "0", "1", "2"
});

// ou avec Object.keys()

Object.keys(arr).forEach(function (element, index) {
  console.log(arr[element]); // affiche "3", "5", "7", "coucou"
  console.log(arr[index]); // affiche "3", "5", "7", undefined
});
```

### Parcourir l'objet `arguments`

Il est possible de parcourir l'objet `arguments` afin d'examiner l'ensemble des paramètres passés à la fonction :


```js
(function () {
  for (let argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);

// 1
// 2
// 3
```

### Parcourir des collections DOM

Il est possible de parcourir des collections DOM telles que `NodeList`. Dans cet exemple, on ajoute une classe `read` aux paragraphes qui sont des descendants directs d'un article :


```js
// Note : Cela ne fonctionnera que pour les plates-formes
// qui implémentent NodeList.prototype[Symbol.iterator]
let articleParagraphs = document.querySelectorAll("article > p");

for (let paragraph of articleParagraphs) {
  paragraph.classList.add("read");
}
```

### Clôturer les itérateurs

Dans les boucles `for...of`, on peut provoquer la fin de l'itérateur avec `break`, `continue`, `throw`, ou `return`. Dans ces cas, l'itérateur est fermé.


```js
function\* toto() {
  yield 1;
  yield 2;
  yield 3;
}

for (let o of toto()) {
  console.log(o);
  break; // L'itérateur est fermé
}
```

### Itérer sur les générateurs

Grâce à cette instruction, on peut également itérer sur les générateurs :


```js
function\* fibonacci() {
  // une fonction génératrice
  let [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // on arrête la séquence à 1000
  if (n >= 1000) {
    break;
  }
}
```

### Itérer sur les autres objets itérables

Il est aussi possible d'itérer sur un objet qui implémente le protocole itérable de façon explicite :


```js
var iterable = {
  [Symbol.iterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return { value: this.i++, done: false };
        }
        return { value: undefined, done: true };
      },
    };
  },
};

for (let value of iterable) {
  console.log(value);
}
console.log("fini !");
// 0
// 1
// 2
```

### Les différences entre `for...of` et `for...in`

Les deux instructions `for...in` et `for...of` permettent de parcourir un ensemble. Mais elles ne parcourent pas le même ensemble.

L'instruction `for...in` permet de parcourir les propriétés énumérables d'un objet dans un ordre arbitraire.

L'instruction `for...of` permet quant à elle de parcourir les données contenues dans l'objet itérable visé.

Dans l'exemple qui suit, on illustre la différence de comportement entre une boucle `for...of` et une boucle `for...in` utilisées sur un tableau (`Array`).


```js
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};

let iterable = [3, 5, 7];
iterable.toto = "coucou";

for (let i in iterable) {
  console.log(i); // affiche 0, 1, 2, "toto",
  // "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // affiche 0, 1, 2, "toto"
  }
}

for (let i of iterable) {
  console.log(i); // affiche 3, 5, 7
}
```


Chaque objet héritera de la propriété `objCustom` et chaque objet qui est un tableau (`Array`) héritera de la propriété `arrCustom` car on les ajoute aux prototypes `Object.prototype` (en-US) et `Array.prototype`. L'objet `iterable` hérite donc des propriétés `objCustom` et `arrCustom` grâce à l'héritage et à la chaîne de prototypes.


```js
for (let i in iterable) {
  console.log(i); // affiche 0, 1, 2, "toto",
  // "arrCustom" et "objCustom"
}
```


Cette boucle ne parcourt que les propriétés énumérables de l'objet `iterable` dans un ordre arbitraire. Les éléments du tableau `3`, `5`, `7` ou `hello` ne sont pas affichés car ce ne sont pas des propriétés (et encore moins des propriétés énumérables). En revanche, on retrouve bien les indices du tableau et les propriétés `arrCustom` et `objCustom`. Pour décrire plus précisément ce comportement, vous pouvez consulter `for...in`.


```js
for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // affiche 0, 1, 2, "toto"
  }
}
```


Cette boucle ressemble à la première mais ajoute la méthode `hasOwnProperty()` qui permet de vérifier si la propriété énumérable recensée est directement disponible sur l'objet (c'est-à-dire si elle n'est pas héritée). La console affiche donc les propriétés `0`, `1`, `2` et `toto` car ce sont des propriétés directement rattachées à l'objet `iterable`. En revanche, les propriétés `arrCustom` et `objCustom` ne sont pas affichées car elles proviennent de l'héritage.


```js
for (let i of iterable) {
  console.log(i); // affiche 3, 5, 7
}
```


Cette boucle parcourt les valeurs définies comme itérables par l'objet itérable et dans ce cas ce sont les éléments du tableau `3`, `5`, `7` et pas les propriétés de l'objet.

### Attention à ne pas réutiliser les générateurs

Les générateurs ne doivent pas être réutilisés, même lorsque la boucle `for...of` a été interrompue (par exemple lorsque `break` est utilisé). Lorsqu'on quitte une boucle, le générateur est clôturé et si on l'utilise à nouveau, il ne fournira aucun résultat. Firefox n'a pas encore implémenté ce comportement standard (cf. bug Firefox 1147371).


```js
var gen = (function\* () {
  yield 1;
  yield 2;
  yield 3;
})();
for (let o of gen) {
  console.log(o);
  break; // L'itérateur est fermé
}

// Le générateur ne doit pas être réutilisé !
for (let o of gen) {
  console.log(o); // Ceci n'est jamais exécuté
}
```

Spécifications
--------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-for-in-and-for-of-statements |

Compatibilité des navigateurs
-----------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Voir aussi
----------

* `Array.prototype.forEach()`
* `Map.prototype.forEach()`