Les boucles dans le code
Les langages de programmation sont très utiles pour effectuer des tâches répétitives, allant de calculs basiques jusqu'à peu près n'importe quelle autre situation où vous avez un certain nombre d'actions similaires à répéter. Ici, nous allons étudier les structures de boucle disponible dans JavaScript qui répondent à un tel besoin.
Prérequis : | Culture informatique basique, compréhension basique du HTML et du CSS, Premiers pas en JavaScript… |
---|---|
Objectif : | Comprendre comment utiliser les boucles dans JavaScript. |
Laissez-moi dans la boucle
Boucles, boucles, boucles. Alors qu'elles sont associées aux cheveux d'une célèbre héroïne de fiction, elles sont également un concept extrêmement important en programmation. Les boucles de programmation ne font que faire la même action encore et toujours, ce qui se traduit par itérer en langage de programmeur.
Commençons par examiner le cas d'un fermier qui doit s'assurer d'avoir assez de nourriture pour nourrir sa famille pour la semaine. Il pourrait ainsi utiliser la boucle suivante :
Une boucle a normalement un ou plusieurs des composants suivants :
- Un compteur, qui est initialisé à une certaine valeur : c'est le point de départ de la boucle ("Départ : Je n'ai pas de nourriture / I have no food", ci-dessus).
- Une condition de sortie, qui est le critère grâce auquel la boucle s'arrête - la plupart du temps, il s'agira d'une certaine valeur que le compteur doit atteindre. Elle est illustrée ci-dessus par "Ai-je assez de nourriture ? / Have I got enough food?". Disons qu'il aura besoin de 10 portions de nourriture pour nourrir sa famille.
- Un itérateur, qui incrémente généralement le compteur petit-à-petit à chaque boucle successive, jusqu'à ce que celui-ci remplisse la condition de sortie. Nous n'avons pas explicitement illustré cela ci-dessus, mais nous pouvons penser que le fermier peut récolter 2 portions de nourriture par heure. On peut donc dire que, toutes les heures, la quantité de nourriture collectée est incrémentée de 2, et il regarde s'il a assez de nourriture. S'il a atteint 10 portions (la condition de sortie), il peut arrêter sa récolte et rentrer chez lui, satisfait de sa journée.
En pseudo-code, cela ressemblerait à ce qui suit :
loop(nourriture = 0; besoinNourriture = 10) {
if (nourriture = besoinNourriture) {
exit loop;
// Nous avons assez de nourriture, on rentre
} else {
nourriture += 2; // On doit rester 1 heure de plus
// La boucle se répète ensuite
}
}
La quantité de nourriture dont le fermier a besoin est donc initialisée à 10, et la quantité dont il dispose est initialisée à 0. À chaque itération de la boucle, on vérifie si la quantité de nourriture dont le fermier dispose est égale à la quantité requise. Si c'est le cas, on peut sortir de la boucle. Sinon, le fermier passe une heure de plus à récolter de la nourriture, et la boucle itère à nouveau.
À quoi ça sert ?
Arrivé à ce stade, vous avez sans doute compris le concept global des boucles, mais vous vous dites probablement : « OK, bien, mais comment cela va-t-il m'aider à améliorer mes codes en JavaScript ? ». Comme nous l'avons dit plus tôt, les boucles ne font rien d'autre que répéter la même action encore et encore, ce qui peut s'avérer utile pour effectuer rapidement des tâches répétitives.
Souvent, le code sera légèrement différent à chaque itération successive, ce qui signifie que vous pouvez effectuer une certaine quantité de tâches similaires, mais néanmoins quelque peu différentes. Si vous avez beaucoup de calculs différents à effectuer, vous n'allez pas effectuer le même calcul encore et encore !
Regardons maintenant un exemple qui illustre parfaitement en quoi les boucles sont si intéressantes. Disons que nous voulons dessiner 100 cercles aléatoirement sur un <canvas>
(appuyez sur le bouton Update pour lancer le programme à nouveau et voir différentes dispositions aléatoires).
Exemple
Principe de boucle
Vous n'avez pas besoin de comprendre entièrement le code pour l'instant, mais regardons plus en détail la partie du code qui trace les 100 cercles :
for (let i = 0; i < 100; i++) {
ctx.beginPath();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();
}
Vous devriez comprendre l'idée basique - nous utilisons une boucle pour effectuer 100 itérations de ce code, chacune dessinant un cercle à une position quelconque sur la page. La quantité de lignes de code nécessaire serait identique si l'on voulait tracer 100 cercles, 1000 ou même 100 000. Seul le nombre d'itérations devrait changer.
Si nous n'utilisions pas de boucle ici, nous aurions dû répéter le code suivant pour chaque cercle que nous aurions voulu dessiner :
ctx.beginPath();
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();
Mais cela prend du temps inutilement, et rend le code difficilement maintenable. Les boucles sont vraiment les meilleures.
La boucle standard
Commençons maintenant à voir quelques formes de boucles spécifiques. La première, celle que vous utiliserez le plus souvent, est la boucle for. Elle a la syntaxe suivante :
for (initialisation; condition de sortie; expression finale) {
// code à exécuter
}
Nous avons ici :
-
Le mot-clé
for
, suivi par des parenthèses. -
A l'intérieur des parenthèses, on a trois objets :
- Une initialisation : il s'agit souvent d'une variable initialisée à une certaine valeur, qui est incrémentée afin de compter le nombre de fois où la boucle s'est exécutée. On peut également la nommer compteur.
- Une condition de sortie : comme mentionné précédemment, cela définit le moment où la boucle doit arrêter de s'exécuter. C'est généralement une expression contenant un opérateur de comparaison, un test pour voir si la condition de sortie est atteinte.
- Une expression finale : elle est toujours évaluée (ou exécutée) chaque fois que la boucle a effectué une itération complète. Cela sert souvent à incrémenter (ou dans certains cas décrémenter) le compteur, pour le rapprocher de la valeur de la condition de sortie.
-
Des accolades contenant un bloc de code : ce code sera exécuté chaque fois que la boucle itère.
Regardons maintenant un vrai exemple, afin de visualiser leurs actions plus clairement.
const chats = ["Bill", "Jeff", "Pete", "Biggles", "Jasmin"];
let info = "Mes chats s'appellent ";
const para = document.querySelector("p");
for (let i = 0; i < chats.length; i++) {
info += chats[i] + ", ";
}
para.textContent = info;
Sortie
Cela nous donne la sortie suivante :
Note : Vous pouvez trouver aussi cet exemple de code sur GitHub (et le voir tourner en live).
Cela montre une boucle utilisée pour itérer sur les éléments d'un tableau et faire quelque chose avec chacun d'eux — un schéma très commun en JavaScript. Ici :
-
L'itérateur,
i
, commence à0
(let i = 0
). -
On lui a demandé de s'exécuter jusqu'à ce que sa valeur ne soit plus inférieure à la longueur du tableau chats. C'est important — la condition de sortie montre la condition à laquelle la boucle continue de s'exécuter. C'est à dire dans ce cas, tant que
i < chats.length
est vrai, la boucle continuera à s'exécuter. -
Au sein de la boucle, on concatène les éléments présents dans cette boucle (
cats[i]
estcats[quelle que soit la valeur de i lors de l'itération]
) avec une virgule et un espace, à la fin de la variableinfo
. Donc :- Pendant le premier lancement,
i = 0
, donccats[0] + ', '
sera concaténé à ("Bill, ") - Au second lancement,
i = 1
, donccats[1] + ', '
et sera concaténé à ("Jeff, ") - Et ainsi de suite. Après chaque tour de boucle, 1 est ajouté à
i
(i++
), et alors le processus recommence encore.
- Pendant le premier lancement,
-
Quand
i
devient égal àcats.length
, la boucle s'arrête, et le navigateur va bouger au prochain bout de code après la boucle.
Note : Nous avons fait sortir la condition i < cats.length
, et pas i <= cats.length
, parce que les ordinateurs comptent à partir de 0, pas 1 — nous avons démarré i
à 0
, et allons allers jusqu'à i = 4
(l'index du dernier item de la table/tableau). cats.length
retourne 5, comme il y a 5 items dans la table, nous n'allons pas itérer jusqu'à i = 5
, cela retournerait undefined
pour le dernier item (il n'y a pas d'élément de tableau avec un index de 5). Par conséquent, nous voulons aller de 1 à moins que cats.length
(i <
), ce n'est pas la même chose que cats.length
(i <=
).
Note : Une erreur commune avec les conditions de sortie est de les faire utiliser "égal à" plutôt que de dire "inférieur ou égal à". Si nous voulions faire tourner notre boucle jusqu'à i = 5, la condition de sortie aurait besoin d'être i <= cats.length / Si nous la mettons à i = cats.length, la boucle ne fonctionnerait pas du tout parce que i n'est pas égal à 5 sur la première itération de la boucle, de sorte que cela s'arrête immédiatement.
Un petit problème est que nous avons laissé la phrase de sortie mal formée :
Mes chats s'appellent Bill, Jeff, Pete, Biggles, Jasmin,
Idéalement, nous voulons changer la concaténation sur l'itération de la boucle finale de sorte que nous n'ayons pas de virgule à la fin de la phrase. Bien, pas de problème, nous pouvons heureusement insérer une structure conditionnelle dans notre boucle for pour gérer ce cas particulier :
for (let i = 0; i < cats.length; i++) {
if (i === cats.length - 1) {
info += "and " + cats[i] + ".";
} else {
info += cats[i] + ", ";
}
}
Note : Vous pouvez trouver cet exemple de code sur GitHub (et aussi le voir en ligne).
Attention : Avec for — comme avec toutes les boucles — vous devez vous assurer que l'initialiseur est itéré de sorte qu'il finisse par atteindre la condition de sortie. Si ce n'est pas le cas, la boucle continuera indéfiniment, et soit le navigateur l'arrêtera, soit il se bloquera. C'est ce qu'on appelle une boucle infinie.
Quitter une boucle avec break
Si vous voulez quitter une boucle avant que toutes les itérations aient été terminées, vous pouvez utiliser l'instruction break
. Nous l'avons déjà rencontré dans l'article précédent lorsque nous examinions les instructions switch
: lorsqu'un argument est rencontré dans une instruction switch qui correspond à l'expression d'entrée, l'instruction break quitte immédiatement l'instruction switch et passe au code après elle.
C'est la même chose avec les boucles : un break
quittera immédiatement la boucle et fera passer le navigateur sur n'importe quel code qui le suit.
Supposons que nous voulions effectuer une recherche parmi une liste de contacts et de numéros de téléphone et que nous ne renvoyions que le nombre que nous voulions trouver. Tout d'abord, du HTML simple - un texte <input>
nous permettant d'entrer un nom à rechercher, un élément <button>
pour soumettre une recherche, et un <p>
élément pour afficher les résultats dans :
<label for="search">Search by contact name: </label>
<input id="search" type="text" />
<button>Search</button>
<p></p>
Maintenant sur le JavaScript :
const contacts = [
"Chris:2232322",
"Sarah:3453456",
"Bill:7654322",
"Mary:9998769",
"Dianne:9384975",
];
const para = document.querySelector("p");
const input = document.querySelector("input");
const bouton = document.querySelector("button");
bouton.addEventListener("click", function () {
let searchName = input.value;
input.value = "";
input.focus();
for (let i = 0; i < contacts.length; i++) {
let splitContact = contacts[i].split(":");
if (splitContact[0] === searchName) {
para.textContent =
splitContact[0] + "'s number is " + splitContact[1] + ".";
break;
} else {
para.textContent = "Contact not found.";
}
}
});
Résultat
-
Tout d'abord, nous avons quelques définitions de variables — nous avons un tableau d'informations de contact, avec chaque élément étant une chaîne contenant un nom et un numéro de téléphone séparés par deux points.
-
Ensuite, nous attachons un écouteur d'événement au bouton (
bouton
), de sorte que quand il est pressé, du code est exécuté pour effectuer la recherche et renvoyer les résultats. -
Nous stockons la valeur saisie dans l'input dans une variable appelée
searchName
, avant de vider l'input et le recentrer, prêt pour la recherche suivante. -
Maintenant sur la partie intéressante, la boucle
for
:- Nous commençons le compteur à
0
, exécutons la boucle jusqu'à ce que le compteur ne soit plus inférieur àcontacts.length
, et incrémentonsi
par 1 après chaque itération de la boucle. - À l'intérieur de la boucle, nous divisons d'abord le contact actuel (
contacts[i]
) au caractère deux-points et stockons les deux valeurs résultantes dans un tableau appelésplitContact
. - Nous utilisons ensuite une instruction conditionnelle pour tester si
splitContact[0]
(le nom du contact) est égal ausearchName
entré. Si c'est le cas, nous introduisons unestring / chaîne de caractère
dans le paragraphe pour indiquer quel est le numéro du contact et utiliserbreak
pour terminer la boucle.
- Nous commençons le compteur à
-
Si le nom du contact ne correspond pas à la recherche entrée, le texte du paragraphe est défini sur "Contact not found." et la boucle continue son itération.
Note : Vous pouvez trouver cet exemple de code sur GitHub (aussi voir en ligne).
Passer des itérations avec continue
L'instruction continue
fonctionne d'une manière similaire à break
, mais au lieu de sortir complètement de la boucle, elle passe à l'itération suivante de la boucle. Regardons un autre exemple qui prend un nombre comme une entrée, et retourne seulement les nombres qui sont des carrés d'entiers (nombres entiers).
Le HTML est fondamentalement le même que le dernier exemple — une entrée de texte simple, et un paragraphe pour la sortie. Le JavaScript est la plupart du temps identique, même si la boucle elle-même est un peu différente :
let num = input.value;
for (let i = 1; i <= num; i++) {
let sqRoot = Math.sqrt(i);
if (Math.floor(sqRoot) !== sqRoot) {
continue;
}
para.textContent += i + " ";
}
Ici la sortie :
- Dans ce cas, l'entrée doit être un nombre (
num
). La bouclefor
est dotée d'un compteur commençant à 1 (car nous ne sommes pas intéressés par 0 dans ce cas), une condition de sortie indiquant que la boucle s'arrêtera lorsque le compteur deviendra plus grand que l'entréenum
, et un itérateur ajoutera 1 au compteur à chaque fois. - À l'intérieur de la boucle, nous trouvons la racine carrée de chaque nombre en utilisant
Math.sqrt(i)
, puis vérifions si la racine carrée est un entier en vérifiant si elle est identique à elle-même lorsqu'elle a été arrondie à l'entier le plus proche (ceci est ce queMath.floor()
fait au nombre auquel il est passé). - Si la racine carrée et la racine carrée arrondie ne sont pas égales les unes aux autres (
! ==
), cela signifie que la racine carrée n'est pas un entier, donc cela ne nous intéresse pas. Dans un tel cas, nous utilisons l'instructioncontinue
pour passer à l'itération de la boucle suivante sans enregistrer le numéro n'importe où. - Si la racine carrée est un entier, nous passons complètement le bloc if pour que l'instruction
continue
ne soit pas exécutée; à la place, nous concaténons la valeuri
actuelle plus un espace sur la fin du contenu du paragraphe.
Note : Vous pouvez trouver cet exemple de code sur GitHub (aussi voir en ligne).
while et do…while
for
n'est pas le seul type de boucle disponible en JavaScript. Il y en a beaucoup d'autres et, même si vous n'avez pas besoin de comprendre tout cela maintenant, il vaut mieux jeter un coup d'œil à la structure de quelques autres pour pouvoir reconnaître les mêmes caractéristiques au travail d'une manière légèrement différente.
D'abord, regardons la boucle while
. La syntaxe de cette boucle ressemble à ceci :
initializer;
while (exit_condition) {
// code to run
final_expression;
}
Cela fonctionne de manière très similaire à la boucle for, sauf que la variable de départ est définie avant la boucle, et l'expression finale est incluse dans la boucle après le code à exécuter, plutôt que ces deux éléments soient inclus dans les parenthèses. La condition de sortie est incluse dans les parenthèses, précédées du mot-clé while
au lieu de for
.
Les mêmes trois éléments sont toujours présents, et ils sont toujours définis dans le même ordre que dans la boucle for
- cela est logique, car vous devez toujours définir un initialiseur avant de pouvoir vérifier s'il a atteint la condition de sortie ; la condition finale est ensuite exécutée après l'exécution du code à l'intérieur de la boucle (une itération a été effectuée), ce qui ne se produira que si la condition de sortie n'a pas encore été atteinte.
Jetons un coup d'œil à notre exemple de liste de chats, mais réécrit pour utiliser une boucle while
:
let i = 0;
while (i < cats.length) {
if (i === cats.length - 1) {
info += "and " + cats[i] + ".";
} else {
info += cats[i] + ", ";
}
i++;
}
Note : Cela fonctionne toujours comme prévu regardez le ici GitHub (Voir en ligne le code complet).
La boucle do…while
est très similaire, mais dénote une variation par rapport à la structure de la boucle while :
initializer;
do {
// code to run
final_expression;
} while (exit_condition);
Dans ce cas, l'initialiseur vient en premier, avant que la boucle ne commence. Le mot-clé do
précède directement les accolades contenant le code à exécuter et l'expression finale.
Le différenciateur ici est que la condition de sortie vient après tout, enveloppée entre parenthèses et précédée d'un mot-clé while
. Dans une boucle do…while
, le code à l'intérieur des accolades est toujours exécuté une fois avant que la vérification ne soit effectuée pour voir si elle doit être exécutée à nouveau (dans while et for, la vérification arrive en premier, donc le code pourrait ne jamais être exécuté).
Réécrivons notre exemple de listing de chat pour utiliser une boucle do…while
:
let i = 0;
do {
if (i === cats.length - 1) {
info += "and " + cats[i] + ".";
} else {
info += cats[i] + ", ";
}
i++;
} while (i < cats.length);
Note : Encore, cela fonctionne toujours comme prévu — regardez le ici GitHub (Voir en ligne le code complet).
Attention : Avec while
et do…while
, comme avec toutes les boucles, vous devez vous assurer que l'initialiseur est itéré pour qu'il atteigne finalement la condition de sortie. Si ce n'est pas le cas, la boucle continuera indéfiniment, et soit le navigateur l'arrêtera, soit il se bloquera. C'est ce qu'on appelle une boucle infinie.
Apprentissage actif : lancer le compte à rebours
Dans cet exercice, nous vous proposons d'écrire un compte à rebours de lancement dans la boîte de sortie, de 10 jusqu'à « Blast Off ». Plus précisément, il s'agit de :
-
Créer une boucle de 10 jusqu'à 0. Nous vous avons fourni un initialiseur —
let i = 10;
-
Pour chaque itération, créer un nouveau paragraphe à ajouter dans la balise de sortie
<div>
que nous avons sélectionnée en utilisant :const output = document.querySelector('.output');
En commentaire, nous vous avons fourni trois lignes de code qui doivent être utilisées quelque part à l'intérieur de la boucle :const para = document.createElement('p');
— crée un nouveau paragraphe.output.appendChild(para);
— ajoute le paragraphe à la sortie<div>
.para.textContent =
— Rend le texte à l'intérieur du paragraphe identique à ce que vous avez entré du côté droit du signe égal.
-
Chaque nombre de l'itération nécessite un texte différent dans le paragraphe de cette itération (vous aurez besoin d'une expression conditionnelle et plusieurs lignes du type :
para.textContent = )
- Si le nombre est 10, écrire « Countdown 10 » dans le paragraphe.
- Si le nombre est 0, écrire « Blast off! » dans le paragraphe.
- Pour tout autre nombre, écrire simplement le nombre dans le paragraphe.
-
N'oubliez pas d'inclure un itérateur ! Quoi qu'il en soit, dans cet exemple nous comptons à rebours après chaque itération, pas de manière croissante, alors vous ne voudrez pas
i++
— Comment allez-vous créer l'itération décroissante ?
Si vous faites une erreur, vous pourrez toujours réinitialiser l'exemple avec le bouton « Reset ». Si vous êtes vraiment bloqué, appuyez sur le bouton "Show solution" pour voir une solution.
Apprentissage actif : remplir une liste d'invités
Dans cet exercice, nous vous proposons de prendre une liste d'invités stockée dans un tableau et de la mettre sur une liste d'invités. Mais cela n'est pas si simple, nous ne voulons pas laisser entrer Phil et Lola parce que ce sont des goinfres et qu'ils sont mal élevés, et ils mangent toujours toute la nourriture ! Nous avons deux listes, une pour les invités admis, une pour ceux que l'on refuse.
Plus précisément, nous attendons de vous :
-
Que vous écriviez une boucle qui crée une itération de 0 jusqu'à la fin du tableau
people
. Vous aurez besoin de commencer avec un initialiseur typelet i = 0;
, mais quelle sera la condition de sortie -
Au cours de chaque itération, vérifiez si l'élément actuel du tableau est "Phil" ou "Lola" en utilisant une déclaration conditionnelle.
- Si tel est le cas, concaténez l'élément à la fin du paragraphe
refused
dutextContent
, suivi d'une virgule et d'un espace. - Dans le cas contraire, concaténez l'élément à la fin du paragraphe
admitted
dutextContent
suivi d'une virgule et d'un espace.
- Si tel est le cas, concaténez l'élément à la fin du paragraphe
Nous vous avons déjà fourni les éléments suivants :
let i = 0;
: votre initialiseur.refused.textContent +=
— le début de la ligne qui va concaténer un élément à la fin durefused.textContent
.admitted.textContent +=
— le début de la ligne qui va concaténer un élément à la fin duadmitted.textContent
.
Question bonus : après avoir accompli les tâches ci-dessus, il vous restera deux listes de noms séparées par des virgules, mais elles seront mal présentées : il y aura des virgules à la fin de chacune d'elles. Pouvez-vous faire en sorte d'écrire des lignes de code qui coupent les dernières virgules dans chacune d'elles, et ajoute un arrêt total à la fin ? Jetez un œil à l'article Méthodes utiles pour les chaînes de caractères pour obtenir de l'aide.
Si vous faites une erreur, vous pourrez toujours ré-initialiser l'exemple avec le bouton « Reset ». Si vous êtes vraiment bloqué, appuyez sur le bouton « Show solution » pour voir une solution.
Quel type de boucle utiliser ?
Pour des usages basiques les boucles for
, while
, et do…while
sont largement interchangeables. Elles résolvent toutes le même problème et celle que vous utiliserez dépendra de vos préférences personnelles, celle que vous trouverez le plus facile à mémoriser ou la plus intuitive. Jetons-y un coup d'œil à nouveau.
Premièrement for
:
for (initialisation; condition de sortie; expression finale) {
// code à exécuter
}
while
:
initialisation
while (condition de sortie) {
// code à exécuter
expression finale
}
et enfin do…while
:
initialisation
do {
// code à exécuter
expression finale
} while (condition de sortie)
Nous recommandons for
, au moins pour commencer, car elle est probablement la plus facile pour tout se remémorer : l'initialisation, la condition de sortie, l'expression finale, le tout soigneusement placé entre des parenthèses. De cette façon, il est facile de voir où elles se trouvent et de vérifier qu'on ne les a pas oubliées.
Note : Il y a d'autres types de boucles et de particularités, qui sont très utiles pour des situations spéciales et qui ne sont pas décrites dans cet article. Si vous voulez aller plus loin dans l'apprentissage des boucles, lisez le guide Boucles et itérations.
Conclusion
Cet article vous a révélé les concepts basiques et les différentes options disponibles pour créer des boucles en JavaScript. Vous devriez à présent être en mesure de comprendre en quoi les boucles constituent un bon mécanisme lorsqu'il s'agit de répéter une action dans le code, et vous devez être impatient de les utiliser dans vos propres exemples !
S'il y a quelque chose que vous n'avez pas compris, n'hésitez pas à relire l'article ou à nous contacter pour demander de l'aide.
Voir aussi
- Boucles et itération
- L'instruction
for
while
etdo…while
break
etcontinue
- What's the Best Way to Write a JavaScript For Loop? (en anglais) — quelques bonnes pratiques en matière de boucles