Avec l'arrivée de nouveaux objets itérables, ECMAScript avait la nécessité de
s'enrichir de nouvelles façons de parcourir ces derniers. Dans l'unique souci de
maintenir la rétro-compatibilité avec l'existant, l'ES6 se devait de garder la
boucle for..in
intacte.
Mais alors, comment créer une variante de cette même boucle avec des capacités améliorées ?
La solution est simple : "Bienvenue au mot-clé of
!"
Mais avant d'en dire plus, et pour comprendre l'utilité de ce nouveau mot-clé, revoyons un peu l'existant.
for..in
Tout JavaScript enthusiast qui se respecte connaissait déjà la fameuse boucle
for..in
dont l'utilité première est d'itérer sur les différentes clés d'un
objet ou d'un tableau.
const obj = { foo: "hello", bar: "world" };
for (const key in obj) {
console.log(key + "->" + obj[key]); // 'foo->hello', 'bar->world'
}
La boucle for..in
, malgré son apparente simplicité d'utilisation, cache
certains pièges :
Lors de l'itération sur un tableau la valeur de l'index est convertie en chaîne de caractères : "0", "1", "2", etc. Cela peut potentiellement poser problème lors de l'utilisation de l'index dans des opérations de calcul.
La boucle itère sur l'ensemble des clés du tableau, mais aussi sur chacune de ses propriétés.
```js
const arr = ['foo', 'bar'];
arr.oups = 'baz';
for ( const key in arr ) {
console.log( key + '->' + arr[key] ); // '0->foo', '1->bar', 'oups->baz'
}
```
L'ordre d'itération sur l'ensemble des clés d'un objet peut varier selon l'environnement d'éxecution du code.
.forEach()
La boucle
Array.prototype.forEach()
permet une itération plus sécurisée, mais présente certains autres inconvénients
tels que :
break;
et return;
for..of
à la rescousseLe consortium ECMA a donc décidé de procéder à la création d'une nouvelle
version améliorée de la boucle for..in
. Ainsi naquit la boucle for..of
qui
coexistera désormais avec la précédente, permettant de maintenir la
rétro-compatibilité avec les versions antérieures de la norme.
Le principe est le même : parcourir n'importe quel type d'objet itérable.
Dans sa forme la plus simple, la boucle for..of
permet donc d'itérer sur
l'ensemble des valeurs des clés d'un tableau.
const arr = ["hello", "world"];
arr.baz = "and mars";
for (const arrValue of arr) {
console.log(arrValue); // 'hello', 'world'
}
La boucle for..of
peut aussi itérer sur des types plus complexes. Examinons
cela de plus près.
Dans ce cas, chaque caractère est traité comme une entité Unicode.
const str = "sm00th";
for (const chr of str) {
console.log(chr); // 's', 'm', '0', '0', 't', 'h'
}
// Note: cela ne fonctionnera que sur les environnements
// implémentant NodeList.prototype[Symbol.iterator]
// ce code ajoute une class "read" à toutes les balises <p>
// contenues dans la(les) balises <article>
const articleParagraphs = document.querySelectorAll("article > p");
for (const paragraph of articleParagraphs) {
paragraph.classList.add("read");
}
const m = new Map([["foo", "hello"], ["bar", "world"]]);
for (const [name, value] of m) {
console.log(name + "->" + value); //"foo->hello", "bar->world"
}
const s = new Set(["foo", true, 42]);
for (const value of s) {
console.log(value); // 'foo', true, 42
}
function* foo() {
yield "foo";
yield false;
yield 42;
yield "bar";
}
for (const v of foo()) {
console.log(v); // 'foo', false, 42, 'bar'
}
Et les objets traditionnels dans tout ça ?
Étonnamment, les objets ne peuvent pas être parcourus avec cette nouvelle boucle
sauf s'ils définissent le symbole Symbol.iterator
. Heureusement, il existe une
solution de contournement par l'utilisation de
Object.keys()
ou encore
d'Object.values()
et
Object.entries()
(ajouts ECMAScript7).
const obj = { foo: "hello", bar: "world" };
for (const key of Object.keys(obj)) {
console.log(key + "->" + obj[key]); // 'foo->hello', 'bar->world'
}
Exemple définissant un itérateur :
const iterableObj = {
*[Symbol.iterator]() {
yield* Object.entries(obj);
},
};
for (const [key, val] of iterableObj) {
console.log(key + "->" + val); // 'foo->hello', 'bar->world'
}
for..of
vient compléter les lacunes de for..in
et permet une itération
simplifiée sur les objets itérables tels que :
De plus, for..of
résout à présent les pièges tels que l'ordre d'itération non
constant ou la coercion automatique des index en chaîne de caractères.
La boucle for..of
est donc une corde de plus à l'arc de l'ES6 qui permet de
parcourir, de manière native, les tout nouveaux objets itérables du langage.
Pour en savoir plus sur ses spécificités :