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

Syntaxe

for (variable of iterable)
  instruction
variable
À chaque itération, la valeur d'une propriété différente est affectée à variable.
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

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 selon leur ordre d'insertion.

L'instruction for...of permet quant à elle de parcourir les données de 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).

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

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 leur ordre d'insertion. Les éléments du tableau 3, 5, 7 ou hello ne sont pas affichés car ce ne sont pas 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.

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.

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.

Utiliser for...of sur un tableau

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 :

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

for (const valeur of tableauItérable) {
  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() :

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 :

(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 :

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

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 :

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 :

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

for (var value of iterable) {
  console.log(value);
}
// 0
// 1
// 2

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 1147371).

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

Spécification État Commentaires
ECMAScript 2015 (6th Edition, ECMA-262)
La définition de 'instruction for...of' dans cette spécification.
Standard Définition initiale.
ECMAScript Latest Draft (ECMA-262)
La définition de 'instruction for...of' dans cette spécification.
Projet  

Compatibilité des navigateurs

Update compatibility data on GitHub
OrdinateurMobileServeur
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebview AndroidChrome pour AndroidEdge MobileFirefox pour AndroidOpera pour AndroidSafari pour iOSSamsung InternetNode.js
Support simpleChrome Support complet 38Edge Support complet 12Firefox Support complet 13
Notes
Support complet 13
Notes
Notes Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
IE Aucun support NonOpera Support complet 25Safari Support complet 8WebView Android Support complet 38Chrome Android Support complet OuiEdge Mobile Support complet 12Firefox Android Support complet 14
Notes
Support complet 14
Notes
Notes Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
Opera Android Support complet 25Safari iOS Support complet 8Samsung Internet Android Support complet Ouinodejs Support complet Oui
async iteratorsChrome Support complet 63Edge ? Firefox Support complet 57IE ? Opera Support complet 50Safari ? WebView Android Support complet 63Chrome Android Support complet 63Edge Mobile ? Firefox Android Support complet 57Opera Android Support complet 50Safari iOS ? Samsung Internet Android ? nodejs ?
Closing iteratorsChrome Support complet 51Edge Support complet OuiFirefox Support complet 53IE Aucun support NonOpera Support complet OuiSafari Support complet OuiWebView Android Support complet OuiChrome Android Support complet OuiEdge Mobile Support complet OuiFirefox Android Support complet 53Opera Android Support complet OuiSafari iOS Support complet OuiSamsung Internet Android Support complet Ouinodejs Support complet Oui

Légende

Support complet  
Support complet
Aucun support  
Aucun support
Compatibilité inconnue  
Compatibilité inconnue
Voir les notes d'implémentation.
Voir les notes d'implémentation.

Voir aussi

Étiquettes et contributeurs liés au document

Dernière mise à jour par : ericGuyaderBerger,