Nous devons souvent répéter les actions.
Par exemple, extraire les produits d'une liste les uns après les autres ou simplement exécuter le même code pour chaque numéro de 1 à 10.
Les boucles sont un moyen de répéter le même code plusieurs fois.
Les boucles for…of et for…in
Une petite annonce pour les lecteurs avancés.
Cet article ne couvre que les boucles de base : while
, do..while
et for(..;..;..)
.
Si vous êtes arrivé à cet article à la recherche d’autres types de boucles, voici les pointeurs :
Voir for…in pour parcourir les propriétés de l'objet.
Voir for…of et itérables pour effectuer une boucle sur des tableaux et des objets itérables.
Sinon, continuez à lire.
La boucle while
a la syntaxe suivante :
tandis que (condition) { //code // ce qu'on appelle "corps de boucle" }
Tant que la condition
est vraie, le code
du corps de la boucle est exécuté.
Par exemple, la boucle ci-dessous génère i
while i < 3
:
soit je = 0 ; while (i < 3) { // affiche 0, puis 1, puis 2 alerte( je ); je++; }
Une seule exécution du corps de la boucle est appelée une itération . La boucle de l'exemple ci-dessus fait trois itérations.
Si i++
manquait dans l'exemple ci-dessus, la boucle se répéterait (en théorie) pour toujours. En pratique, le navigateur fournit des moyens d'arrêter de telles boucles, et en JavaScript côté serveur, nous pouvons tuer le processus.
Toute expression ou variable peut être une condition de boucle, pas seulement des comparaisons : la condition est évaluée et convertie en booléen par while
.
Par exemple, une façon plus courte d'écrire while (i != 0)
est while (i)
:
soit je = 3; while (i) { // quand i devient 0, la condition devient fausse et la boucle s'arrête alerte( je ); je--; }
Les accolades ne sont pas nécessaires pour un corps à une seule ligne
Si le corps de la boucle contient une seule instruction, nous pouvons omettre les accolades {…}
:
soit je = 3; tandis que (i) alert(i--);
La vérification de condition peut être déplacée sous le corps de la boucle en utilisant la syntaxe do..while
:
faire { // corps de la boucle } while (condition);
La boucle exécutera d'abord le corps, puis vérifiera la condition et, tant qu'elle est véridique, l'exécutera encore et encore.
Par exemple:
soit je = 0 ; faire { alerte( je ); je++; } tandis que (je < 3);
Cette forme de syntaxe ne doit être utilisée que lorsque vous souhaitez que le corps de la boucle s'exécute au moins une fois, quelle que soit la condition de véracité. Habituellement, l'autre forme est préférée : while(…) {…}
.
La boucle for
est plus complexe, mais c'est aussi la boucle la plus couramment utilisée.
Cela ressemble à ceci :
pour (début ; condition ; étape) { // ... corps de la boucle ... }
Apprenons la signification de ces parties par exemple. La boucle ci-dessous exécute alert(i)
pour i
de 0
à (mais non compris) 3
:
for (let i = 0; i < 3; i++) { // affiche 0, puis 1, puis 2 alerte(i); }
Examinons l'instruction for
partie par partie :
partie | ||
---|---|---|
commencer | let i = 0 | S'exécute une fois lors de l'entrée dans la boucle. |
condition | i < 3 | Vérifié avant chaque itération de boucle. Si faux, la boucle s'arrête. |
corps | alert(i) | Fonctionne encore et encore tant que l'état est véridique. |
étape | i++ | S'exécute après le corps à chaque itération. |
L'algorithme de boucle générale fonctionne comme ceci :
Exécuter commencer → (si condition → exécuter le corps et exécuter l'étape) → (si condition → exécuter le corps et exécuter l'étape) → (si condition → exécuter le corps et exécuter l'étape) → ...
Autrement dit, begin
s'exécute une fois, puis itère : après chaque test condition
, body
et step
sont exécutés.
Si vous débutez avec les boucles, il peut être utile de revenir à l'exemple et de reproduire son fonctionnement étape par étape sur une feuille de papier.
Voici exactement ce qui se passe dans notre cas :
// pour (soit i = 0; i < 3; i++) alert(i) // début de l'exécution soit je = 0 // si condition → exécuter le corps et exécuter l'étape si (i < 3) { alerte (i); je++ } // si condition → exécuter le corps et exécuter l'étape si (i < 3) { alerte (i); je++ } // si condition → exécuter le corps et exécuter l'étape si (i < 3) { alerte (i); je++ } // ...terminer, car maintenant i == 3
Déclaration de variable en ligne
Ici, la variable « compteur » i
est déclarée directement dans la boucle. C'est ce qu'on appelle une déclaration de variable « en ligne ». Ces variables ne sont visibles qu'à l'intérieur de la boucle.
pour (soit i = 0; i < 3; i++) { alerte(i); // 0, 1, 2 } alerte(i); // erreur, aucune variable de ce type
Au lieu de définir une variable, nous pourrions en utiliser une existante :
soit je = 0 ; for (i = 0; i < 3; i++) { // utiliser une variable existante alerte(i); // 0, 1, 2 } alerte(i); // 3, visible, car déclaré en dehors de la boucle
N'importe quelle partie de for
peut être ignorée.
Par exemple, nous pouvons omettre begin
si nous n'avons rien à faire au début de la boucle.
Comme ici :
soit je = 0 ; // nous avons déjà déclaré et attribué for (; i < 3; i++) { // pas besoin de "begin" alerte( je ); // 0, 1, 2 }
Nous pouvons également supprimer la partie step
:
soit je = 0 ; pour (; je < 3;) { alerte( i++ ); }
Cela rend la boucle identique à while (i < 3)
.
Nous pouvons en fait tout supprimer, créant une boucle infinie :
pour (;;) { // se répète sans limites }
Veuillez noter que les deux for
les points-virgules ;
doit être présent. Sinon, il y aurait une erreur de syntaxe.
Normalement, une boucle se termine lorsque sa condition devient fausse.
Mais nous pouvons forcer la sortie à tout moment en utilisant la directive spéciale break
.
Par exemple, la boucle ci-dessous demande à l’utilisateur une série de nombres, « cassante » lorsqu’aucun nombre n’est saisi :
soit somme = 0 ; tandis que (vrai) { let value = +prompt("Entrez un nombre", ''); si (!value) pause ; // (*) somme += valeur ; } alert( 'Somme : ' + somme );
La directive break
est activée à la ligne (*)
si l'utilisateur saisit une ligne vide ou annule la saisie. Il arrête la boucle immédiatement, passant le contrôle à la première ligne après la boucle. A savoir, alert
.
La combinaison « boucle infinie + break
selon les besoins » est idéale pour les situations où l'état d'une boucle doit être vérifié non pas au début ou à la fin de la boucle, mais au milieu ou même à plusieurs endroits de son corps.
La directive continue
est une « version allégée » de break
. Cela n'arrête pas toute la boucle. Au lieu de cela, il arrête l'itération en cours et force la boucle à en démarrer une nouvelle (si la condition le permet).
Nous pouvons l'utiliser si nous en avons terminé avec l'itération en cours et que nous souhaitons passer à la suivante.
La boucle ci-dessous utilise continue
pour générer uniquement des valeurs impaires :
pour (soit i = 0; i < 10; i++) { // si c'est vrai, ignore la partie restante du corps si (i % 2 == 0) continuer ; alerte(i); // 1, puis 3, 5, 7, 9 }
Pour les valeurs paires de i
, la directive continue
arrête l'exécution du corps et passe le contrôle à l'itération suivante de for
(avec le numéro suivant). L' alert
n'est donc appelée que pour les valeurs impaires.
La directive continue
aide à réduire l'imbrication
Une boucle affichant des valeurs impaires pourrait ressembler à ceci :
pour (soit i = 0; i < 10; i++) { si (je % 2) { alerte( je ); } }
D'un point de vue technique, ceci est identique à l'exemple ci-dessus. Nous pouvons sûrement simplement envelopper le code dans un bloc if
au lieu d'utiliser continue
.
Mais comme effet secondaire, cela a créé un niveau d'imbrication supplémentaire (l'appel alert
à l'intérieur des accolades). Si le code à l’intérieur de if
est plus long que quelques lignes, cela peut diminuer la lisibilité globale.
Pas break/continue
vers la droite de « ? »
Veuillez noter que les constructions syntaxiques qui ne sont pas des expressions ne peuvent pas être utilisées avec l'opérateur ternaire ?
. En particulier, les directives telles que break/continue
n'y sont pas autorisées.
Par exemple, si l'on prend ce code :
si (je > 5) { alerte(i); } autre { continuer; }
…et réécrivez-le en utilisant un point d’interrogation :
(je > 5) ? alert(i) : continuer ; // continuer n'est pas autorisé ici
…ça ne marche plus : il y a une erreur de syntaxe.
C'est juste une autre raison de ne pas utiliser l'opérateur point d'interrogation ?
au lieu de if
.
Parfois, nous devons sortir de plusieurs boucles imbriquées à la fois.
Par exemple, dans le code ci-dessous, nous parcourons i
et j
, en demandant les coordonnées (i, j)
de (0,0)
à (2,2)
:
pour (soit i = 0; i < 3; i++) { pour (soit j = 0; j < 3; j++) { let input = prompt(`Valeur aux coordonnées (${i},${j})`, ''); // et si nous voulons sortir d'ici vers Done (ci-dessous) ? } } alert('Terminé !');
Nous avons besoin d'un moyen d'arrêter le processus si l'utilisateur annule la saisie.
La break
ordinaire après input
ne ferait que briser la boucle interne. Cela ne suffit pas : les étiquettes, venez à la rescousse !
Une étiquette est un identifiant avec deux points avant une boucle :
labelName : pour (...) { ... }
L'instruction break <labelName>
dans la boucle ci-dessous se décompose en étiquette :
externe : pour (soit i = 0 ; i < 3 ; i++) { pour (soit j = 0; j < 3; j++) { let input = prompt(`Valeur aux coordonnées (${i},${j})`, ''); // s'il s'agit d'une chaîne vide ou annulée, alors sortez des deux boucles if (!input) break external; // (*) // fait quelque chose avec la valeur... } } alert('Terminé !');
Dans le code ci-dessus, break outer
recherche vers le haut l'étiquette nommée outer
et sort de cette boucle.
Ainsi, le contrôle passe directement de (*)
à alert('Done!')
.
Nous pouvons également déplacer l'étiquette sur une ligne distincte :
extérieur: pour (soit i = 0; i < 3; i++) { ... }
La directive continue
peut également être utilisée avec une étiquette. Dans ce cas, l’exécution du code passe à l’itération suivante de la boucle étiquetée.
Les étiquettes ne permettent pas de « sauter » n’importe où
Les étiquettes ne nous permettent pas d'accéder à un endroit arbitraire du code.
Par exemple, il est impossible de faire ceci :
casser l'étiquette ; // passe à l'étiquette ci-dessous (ne fonctionne pas) étiquette : pour (...)
Une directive break
doit être à l’intérieur d’un bloc de code. Techniquement, n'importe quel bloc de code étiqueté fera l'affaire, par exemple :
étiquette: { //... casser l'étiquette ; // travaux //... }
… Bien que 99,9 % de la break
temporelle soit utilisée dans des boucles, comme nous l'avons vu dans les exemples ci-dessus.
Une continue
n'est possible qu'à l'intérieur d'une boucle.
Nous avons couvert 3 types de boucles :
while
– La condition est vérifiée avant chaque itération.
do..while
– La condition est vérifiée après chaque itération.
for (;;)
– La condition est vérifiée avant chaque itération, paramètres supplémentaires disponibles.
Pour créer une boucle « infinie », la construction while(true)
est généralement utilisée. Une telle boucle, comme n’importe quelle autre, peut être arrêtée avec la directive break
.
Si nous ne voulons rien faire dans l'itération en cours et souhaitons passer à la suivante, nous pouvons utiliser la directive continue
.
break/continue
les étiquettes de support avant la boucle. Une étiquette est le seul moyen pour break/continue
d'échapper à une boucle imbriquée pour accéder à une boucle externe.
importance : 3
Quelle est la dernière valeur alertée par ce code ? Pourquoi?
soit je = 3; tandis que (i) { alerte( je-- ); }
La réponse : 1
.
soit je = 3; tandis que (i) { alerte( je-- ); }
Chaque itération de boucle diminue i
de 1
. La vérification while(i)
arrête la boucle lorsque i = 0
.
Ainsi, les étapes de la boucle forment la séquence suivante (« boucle déroulée ») :
soit je = 3; alerte(i--); // affiche 3, diminue i à 2 alert(i--) // affiche 2, diminue i à 1 alert(i--) // affiche 1, diminue i à 0 // terminé, while(i) check arrête la boucle
importance : 4
Pour chaque itération de boucle, notez la valeur qu'elle génère, puis comparez-la avec la solution.
Les deux boucles alert
les mêmes valeurs, ou pas ?
La forme du préfixe ++i
:
soit je = 0 ; while (++i < 5) alert( i );
La forme suffixe i++
soit je = 0 ; while (i++ < 5) alert( i );
La tâche montre comment les formulaires suffixe/préfixe peuvent conduire à des résultats différents lorsqu'ils sont utilisés dans des comparaisons.
De 1 à 4
soit je = 0 ; while (++i < 5) alert( i );
La première valeur est i = 1
, car ++i
incrémente d'abord i
puis renvoie la nouvelle valeur. La première comparaison est donc 1 < 5
et l' alert
affiche 1
.
Suivez ensuite 2, 3, 4…
– les valeurs apparaissent les unes après les autres. La comparaison utilise toujours la valeur incrémentée, car ++
est avant la variable.
Enfin, i = 4
est incrémenté à 5
, la comparaison while(5 < 5)
échoue et la boucle s'arrête. Donc 5
n’est pas affiché.
De 1 à 5
soit je = 0 ; while (i++ < 5) alert( i );
La première valeur est encore une fois i = 1
. La forme suffixe de i++
incrémente i
puis renvoie l' ancienne valeur, donc la comparaison i++ < 5
utilisera i = 0
(contrairement à ++i < 5
).
Mais l’appel alert
est distinct. C'est une autre instruction qui s'exécute après l'incrément et la comparaison. Il obtient donc le courant i = 1
.
Suivez ensuite 2, 3, 4…
Arrêtons-nous sur i = 4
. La forme du préfixe ++i
l'incrémenterait et utiliserait 5
dans la comparaison. Mais ici, nous avons la forme postfixée i++
. Donc, il incrémente i
à 5
, mais renvoie l'ancienne valeur. Par conséquent, la comparaison est en fait while(4 < 5)
– vraie, et le contrôle passe à alert
.
La valeur i = 5
est la dernière, car à l'étape suivante while(5 < 5)
est faux.
importance : 4
Pour chaque boucle, notez les valeurs qu'elle va afficher. Comparez ensuite avec la réponse.
Les deux boucles alert
les mêmes valeurs ou non ?
La forme suffixe :
pour (soit i = 0; i < 5; i++) alert( i );
La forme du préfixe :
pour (soit i = 0; i < 5; ++i) alert( i );
La réponse : de 0
à 4
dans les deux cas.
pour (soit i = 0; i < 5; ++i) alert( i ); pour (soit i = 0; i < 5; i++) alert( i );
Cela peut être facilement déduit de l'algorithme de for
:
Exécuter une fois i = 0
avant tout (commencer).
Vérifier la condition i < 5
Si true
– exécutez l’ alert(i)
, puis i++
L'incrément i++
est séparé du contrôle de condition (2). C'est juste une autre déclaration.
La valeur renvoyée par l'incrément n'est pas utilisée ici, il n'y a donc aucune différence entre i++
et ++i
.
importance : 5
Utilisez la boucle for
pour générer des nombres pairs de 2
à 10
.
Exécutez la démo
pour (soit i = 2; i <= 10; i++) { si (je % 2 == 0) { alerte( je ); } }
Nous utilisons l'opérateur « modulo » %
pour obtenir le reste et vérifier la régularité ici.
importance : 5
Réécrivez le code en changeant la boucle for
en while
sans modifier son comportement (la sortie doit rester la même).
pour (soit i = 0; i < 3; i++) { alert( `numéro ${i}!` ); }
soit je = 0 ; tandis que (i < 3) { alert( `numéro ${i}!` ); je++; }
importance : 5
Écrivez une boucle qui demande un nombre supérieur à 100
. Si le visiteur saisit un autre numéro, demandez-lui de le saisir à nouveau.
La boucle doit demander un nombre jusqu'à ce que le visiteur saisisse un nombre supérieur à 100
ou annule la saisie/entre une ligne vide.
Ici, nous pouvons supposer que le visiteur ne saisit que des chiffres. Il n'est pas nécessaire d'implémenter une gestion spéciale pour une entrée non numérique dans cette tâche.
Exécutez la démo
laissez num; faire { num = prompt("Entrez un nombre supérieur à 100 ?", 0); } while (num <= 100 && num);
La boucle do..while
se répète tant que les deux vérifications sont véridiques :
La vérification de num <= 100
– c'est-à-dire que la valeur saisie n'est toujours pas supérieure à 100
.
La vérification && num
est fausse lorsque num
est null
ou une chaîne vide. Ensuite, la boucle while
s'arrête également.
PS Si num
est null
alors num <= 100
est true
, donc sans la deuxième vérification, la boucle ne s'arrêterait pas si l'utilisateur clique sur ANNULER. Les deux contrôles sont obligatoires.
importance : 3
Un nombre entier supérieur à 1
est appelé premier s’il ne peut être divisé sans reste par autre chose que 1
et lui-même.
En d'autres termes, n > 1
est un nombre premier s'il ne peut être divisé uniformément par autre chose que 1
et n
.
Par exemple, 5
est un nombre premier, car il ne peut être divisé sans reste par 2
, 3
et 4
.
Écrivez le code qui génère des nombres premiers dans l'intervalle de 2
à n
.
Pour n = 10
le résultat sera 2,3,5,7
.
PS Le code devrait fonctionner pour n'importe quel n
, et ne pas être réglé en profondeur pour une valeur fixe.
Il existe de nombreux algorithmes pour cette tâche.
Utilisons une boucle imbriquée :
Pour chaque i dans l'intervalle { vérifie si j'ai un diviseur de 1..i si oui => la valeur n'est pas première si non => la valeur est première, montrez-la }
Le code utilisant une étiquette :
soit n = 10 ; suivantPrime : for (let i = 2; i <= n; i++) { // pour chaque i... for (let j = 2; j < i; j++) { // cherche un diviseur.. si (i % j == 0) continue nextPrime ; // pas un nombre premier, passe ensuite i } alerte( je ); // un premier }
Il y a beaucoup d'espace pour l'optimiser. Par exemple, nous pourrions rechercher les diviseurs de 2
à la racine carrée de i
. Mais quoi qu'il en soit, si nous voulons être vraiment efficaces sur de grands intervalles, nous devons changer d'approche et nous appuyer sur des mathématiques avancées et des algorithmes complexes comme le tamis quadratique, le tamis général de champ numérique, etc.