Apprenez en lisant dans l'ordre

Boucles — for, for...of et for...in

Les boucles JavaScript : for pour compter, for...of pour les éléments, for...in pour les clés, et les boucles imbriquées.

Pour afficher le prix de chaque article commandé sur sa propre ligne, il faudrait écrire la même ligne 3 fois pour 3 articles, et 10 fois pour 10. Le nombre d'articles dépend des données : impossible de savoir à l'avance combien de lignes il te faudra.

Cet article couvre for, qui répète en comptant, for...of, qui te donne les éléments un par un, et for...in, qui parcourt les clés.

Répéter du code pour chaque article — les trois expressions de for

Imaginons que tu veuilles afficher le nom des articles d'une commande, un par ligne. Si tu les écris un à un, en commençant par console.log(orderLines[0]), il faudra ajouter une ligne dès que la commande passe à 4 articles, et modifier le code chaque fois que le nombre change.

Une boucle for (une instruction qui répète le même code en comptant) prend entre ses parenthèses trois expressions séparées par des points-virgules, et le code à répéter se place entre les accolades. Ce qui se trouve entre ces accolades s'appelle le corps. De gauche à droite, les trois expressions sont l'initialisation, la condition et la mise à jour : la condition est testée avant d'entrer dans le corps, et la mise à jour s'exécute après le corps.

i++ a le même sens que i = i + 1. Comme sa valeur change à chaque tour, i est déclaré avec let.

const orderLines = ["Mug", "Carnet", "Stylo bille"];   // noms des articles de la commande

// i part de 0 et augmente de 1 avec i++ jusqu'à atteindre le nombre d'articles
for (let i = 0; i < orderLines.length; i++) {
  // Les index commencent à 0 : on affiche i + 1 pour compter à partir de l'article 1
  console.log(`Article ${i + 1} : ${orderLines[i]}`);
}
// Article 1 : Mug
// Article 2 : Carnet
// Article 3 : Stylo bille

console.log(`Articles affichés : ${orderLines.length}`);   // Articles affichés : 3
Un tour de boucle for
Initialiserlet i = 0Conditioni < 3Corpsaffiche1 articleMise à jouri++Fin dela bouclevrainouveau testfaux

L'initialisation ne s'exécute qu'une fois, tout au début ; la condition s'exécute avant le corps, et la mise à jour après le corps. Au tour où la condition devient fausse, la boucle se termine sans exécuter le corps.

Tester la condition, exécuter le corps puis la mise à jour : l'ensemble forme un tour (une itération). Comme la mise à jour s'exécute après le corps, i est toujours égal au nombre de fois où le corps s'est déjà exécuté en entier ; au premier tour, le corps s'exécute donc avec i encore à 0.

Le tableau ci-dessous montre i et le test de la condition à chaque tour.

TourValeur de i et conditionCe qui se passe dans le corps
Tour 1i = 0 / 0 < 3 est vraiArticle 1 : Mug
Tour 2i = 1 / 1 < 3 est vraiArticle 2 : Carnet
Tour 3i = 2 / 2 < 3 est vraiArticle 3 : Stylo bille
Début du tour 4i = 3 / 3 < 3 est fauxLe corps ne s'exécute pas, la boucle se termine

Lire au-delà de la fin d'un tableau donne undefined

Si tu écris la condition i <= orderLines.length, tu obtiens un tour de trop à la fin, qui lit orderLines[3] — un élément qui n'existe pas. Tout ce qui est hors limites vaut undefined : tu verras donc « Article 4 : undefined », et si la boucle additionne des prix, le résultat devient NaN. Ne fais tourner la boucle que tant que l'index est inférieur au nombre d'articles.

Additionne les prix des articles d'un panier. Le tableau de prix unitPrices est déjà déclaré.

① Prépare une variable pour le total, initialisée à 0.

② Avec for, compte à partir de 0 et ajoute chaque prix au total.

③ Affiche le total sous la forme « Total : ◯◯ yens ».

④ Divise par le nombre d'articles pour obtenir la moyenne, arrondis à l'entier inférieur, et affiche-la sous la forme « Moyenne : ◯◯ yens ».

(Si tout s'exécute correctement, une explication apparaîtra.)

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

Récupérer chaque élément directement — for...of et entries

Prenons une liste de numéros de commande en attente d'expédition, à traiter l'un après l'autre. Avec for, il faut déclarer une variable d'index, écrire la condition et la mise à jour, puis lire chaque numéro avec orderIds[i] — et une faute de frappe dans l'index suffit à lire le mauvais élément.

for...of (une instruction qui prend un par un les éléments d'un tableau ou d'un autre itérable et place chacun dans une variable) s'écrit for (const orderId of orderIds), avec seulement la déclaration et le tableau entre les parenthèses.

Si tu as aussi besoin de la position, boucle sur orderIds.entries(). À chaque tour, tu obtiens une paire comme [0, "A-1001"], que tu décomposes avec des crochets : [index, orderId].

const orderIds = ["A-1001", "A-1002", "A-1003"];   // numéros de commande en attente d'expédition

// orderId contient l'élément lui-même (aucun index en vue)
for (const orderId of orderIds) {
  console.log(`En attente d'expédition : ${orderId}`);
}
// En attente d'expédition : A-1001 … (3 lignes)

// Si tu as aussi besoin de l'index, récupère des paires avec entries()
for (const [index, orderId] of orderIds.entries()) {
  console.log(`#${index + 1} : ${orderId}`);
}
// #1 : A-1001
// #2 : A-1002
// #3 : A-1003
RéceptionContenu de la variableLigne affichée
Éléments via ofL'élément lui-même (A-1001)En attente d'expédition : A-1001
entries() en [index, orderId]index : 0 / orderId : A-1001#1 : A-1001
entries() dans une variableLa paire index-élémentLe tableau [0, "A-1001"] tel quel

const [index, orderId] fonctionne comme la décomposition de tableaux vue dans l'article sur la déstructuration : l'index va à la première position, l'élément à la seconde. Une nouvelle variable est créée à chaque tour, tu peux donc déclarer la variable de boucle d'un for...of avec const sans provoquer d'erreur de réaffectation.

Repère les commandes qui ne sont pas encore arrivées dans une liste de statuts de livraison. Le tableau deliveries est déjà déclaré ; chaque commande a un numéro de commande (id) et un statut (status).

① Avec for...of, récupère les commandes une par une et affiche chacune sous la forme « A-1001 : Livrée ».

② Parcours de nouveau la liste en récupérant aussi la position, et n'affiche que les commandes non livrées, sous la forme « #2 A-1002 : En cours de livraison ».

③ Compte combien de commandes tu as affichées en ②, et affiche à la fin « Non livrées : ◯ ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

Parcourir les clés — for...in, et pourquoi l'éviter sur un tableau

Il arrive qu'on veuille afficher côte à côte le nom des clés et leurs valeurs, par exemple pour un profil de membre. Tu pourrais transformer les clés en tableau avec Object.keys(profile) puis le parcourir avec for...of, mais si tu veux seulement parcourir les clés, il existe une écriture plus courte.

for...in (une instruction qui parcourt une à une les clés d'un objet) s'écrit for (const key in profile). La variable contient la clé sous forme de chaîne, et non la valeur : tu lis donc la valeur avec la notation entre crochets, comme profile[key].

const profile = { displayName: "Léa", plan: "premium", posts: 12 };

// key contient la clé sous forme de chaîne (pas la valeur)
for (const key in profile) {
  console.log(`${key}: ${profile[key]}`);
}
// displayName: Léa
// plan: premium
// posts: 12

// Sur un tableau, les index arrivent sous forme de chaînes
const stockCounts = [5, 0, 12];
for (const key in stockCounts) {
  console.log(`${typeof key} / ${key + 1}`);
}
// string / 01
// string / 11
// string / 21   ← concaténés comme des chaînes, pas additionnés comme des nombres
for...in te donne des clés
Objetprofilekey contientla cléprofile[key]lit la valeurplan: premiumTableaustockCountskey vaut"0" "1" "2"key + 1concatèneDonne "01"
Avec un objet, tu obtiens chaque clé sous forme de chaîne ; avec un tableau, chaque index sous forme de chaîne. Sur un tableau, key + 1 ne fait pas d'addition : cela concatène des chaînes.

Si tu ne fais que lire des éléments, comme avec stockCounts[key], la chaîne "1" te donne quand même la valeur. Tu pourrais la convertir avec Number(key) pour l'utiliser dans un calcul, mais pour les éléments d'un tableau, il est plus simple de choisir dès le départ une autre boucle. Le tableau ci-dessous indique quand utiliser chacune des trois.

SyntaxeContenu de la variableIdéal pour
for (let i = 0; i < count; i++)L'index (nombre)Utiliser la position dans un calcul
for (const item of array)L'élément lui-mêmeTraiter les éléments dans l'ordre
for (const key in object)La clé (chaîne)Parcourir les clés d'un objet

Impossible de parcourir un objet avec for...of

Si tu places un objet à droite de of, comme dans for (const item of profile), l'exécution s'arrête sur TypeError: profile is not iterable. Les objets simples ne sont pas itérables : ils ne définissent aucun moyen de livrer leur contenu un élément à la fois. Pour parcourir aussi les valeurs, transforme d'abord l'objet en tableau avec Object.entries.

Sur un écran de modification de profil, compare le profil avant et après l'enregistrement, et n'affiche que les champs modifiés. before (les anciennes valeurs) et after (les nouvelles) sont déjà déclarées.

① Prépare une variable initialisée à 0 pour compter les champs modifiés.

② Avec for...in, parcours une à une les clés de before.

③ Lis la nouvelle valeur avec la même clé et, pour les champs dont la valeur diffère, affiche-les sous la forme « city: Yokohama -> Kawasaki » et compte-les.

④ À la fin, affiche « Champs modifiés : ◯ ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

Lister toutes les combinaisons — boucle interne et boucle externe

Tu veux maintenant lister les produits proposés par chaque magasin, sous forme de toutes les combinaisons magasin-produit. Une seule boucle peut parcourir soit les magasins, soit les produits, mais pas les deux à la fois. Et le nombre de magasins comme le nombre de produits dépendent des données.

Tu peux placer une autre boucle directement dans le corps d'une boucle. La boucle interne s'exécute entièrement à chaque tour de la boucle externe : le corps interne s'exécute donc le nombre de tours externes multiplié par le nombre de tours internes. La boucle interne peut aussi lire directement la variable de la boucle externe.

const stores = ["Shibuya", "Yokohama"];
const products = ["Mug", "Carnet"];

// À chaque tour de la boucle externe, la boucle interne s'exécute entièrement
for (const store of stores) {
  for (const product of products) {
    console.log(`${store} / ${product}`);
  }
}
// Shibuya / Mug
// Shibuya / Carnet
// Yokohama / Mug
// Yokohama / Carnet
Les variables que la boucle interne peut lire
for...of externe (un tour par magasin)
  • store — passe de "Shibuya" à "Yokohama" à chaque tour
  • Le corps externe ne s'exécute que 2 fois
for...of interne (tous les produits)
  • product — passe de "Mug" à "Carnet" à chaque tour interne
  • Peut lire directement le store externe
  • Ce corps s'exécute 2 × 2 = 4 fois
Le corps interne peut lire à la fois product, de la boucle interne, et store, de la boucle externe. product, déclarée dans la boucle interne, n'est utilisable qu'entre les accolades internes.

Le for...of interne repart du début de products chaque fois que le tour externe change : tant que store reste le même, seul product change. Une variable déclarée au début du corps externe est elle aussi recréée à chaque tour externe. La façon dont les accolades limitent l'endroit où une variable est utilisable est traitée dans l'article sur la portée.

Additionne les prix des lignes de chaque commande. Le tableau orders est déjà déclaré ; chaque commande a un numéro de commande (id) et un tableau des prix de ses lignes (prices).

① Avec une boucle externe, parcours les commandes une par une.

② Prépare une variable de sous-total pour chaque commande, de sorte qu'elle reparte de 0 à chaque nouvelle commande.

③ Avec une boucle interne, parcours les prix de cette commande et ajoute chacun au sous-total.

④ Après la boucle interne, affiche une ligne de la forme « A-1001 : qté 2 / 1760 yens ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Quand tu parcours orderIds.entries() avec for...of, que vaut index au premier tour ?

Question 2Quand tu parcours un tableau avec for...in, que contient la variable de boucle ?

Question 3Si tu parcours un tableau de 3 éléments et un tableau de 4 éléments dans une boucle imbriquée, combien de fois le corps interne s'exécute-t-il ?