Programmation JavaScript/Structures de contrôle

JavaScript dispose de structures de contrôle comparables à ce qu'on rencontre en langage C. La plupart des règles et habitudes acquises dans ce langage sont immédiatement transposables en JavaScript.

Avant de passer en revue les structures de contrôle, il est utile de lire le paragraphe Établissement d'une expression logique qui précise certains aspects de la méthode.

Établissement d'une expression logique

modifier

L'usage de if, while et do met en œuvre des expressions logiques dont le résultat testé (vrai) conditionnera l'exécution de l'instruction ou du bloc d'instructions associé.
Ces expressions logiques sont inscrites entre parenthèses.
Du plus simple au plus complexe, on trouve :

  • (5 == 5) est bizarre mais vrai
  • (true) La constante true est toujours vraie
  • (false) La constante false est toujours fausse
  • (var_bool) Si var_bool est vrai, l'expression est vraie
  • (!var_bool)Si var_bool est vrai, l'expression est fausse
  • (var_bool==false) Si var_bool est faux, l'expression est vraie (et oui...)

Avec des variables numériques ou des variables chaînes, le principe est similaire :

  • (ma_var_num == 5)
  • (ma_chaine == "foo")

De même avec les opérateurs de comparaison :

  • (ma_var > 0) ma_var non nulle
  • (ma_var <= 5) inférieure ou égale à 5
  • (ma_chaine != "bar") le contenu de ma_chaine différent de "bar"

etc..
À l'étape suivante, on peut combiner des expressions logiques avec des opérateurs logiques ET ( && ) et OU (||).

  • ((ma_var==5)&&(ma_chaine=="bar")) Réaliser les deux conditions
  • ((ma_var==5)||(ma_chaîne=="bar")) Réaliser l'une des conditions
  • ((ma_var==5)&&(ma_chaine=="bar")||(!var_bool))

... Et ainsi de suite... en faisant très attention aux parenthèses et à l'ordre de priorité des opérateurs, et à conserver une certaine lisibilité au code.

Le piège

modifier

L'auteur de cet article ne vient pas du C , mais du pascal. Il commet donc encore aujourd'hui l'erreur de confondre l'opérateur d'affectation avec l'opérateur d'égalité logique. Ceci a pour conséquence d'introduire un bug à retardement dû à l'affectation de la variable de test.

if (ma_var = 0) Exécution du code

L'expression (ma_var = 0) est fausse. L'expression (ma_var = 5) est vraie. Mais dans les deux cas, l'affectation a lieu, écrasant le contenu précédent de la variable.
Donc cette erreur, si elle n'est pas comprise, plonge le programmeur dans des abîmes de questions et de doutes, avec peu de chances de comprendre pourquoi. Bien entendu, la bonne façon est d'utiliser l'opérateur d'égalité logique ( == ) à la place de l'opérateur d'affectation ( = ). La valeur de l'opération d'affectation peut cependant être utilisée volontairement. Voir la section sur l'opérateur =.

Branchement conditionnel

modifier

if else

modifier

La structure de contrôle if permet de subordonner l'exécution d'une ligne ou d'un bloc d'instructions à l'évaluation (vrai) d'une expression logique.
La syntaxe est :

Exemple if
if (condition_vrai) // Exécution d'une ligne d'instructions
    alert("La condition est vraie");
.
.
.
if (condition_vrai) // Exécution d'un bloc d'instructions
{
    alert("La condition est vrai");
    alert("... je le confirme");
}

Le mot réservé else permet d'exécuter une ligne ou un bloc d'instructions alternativement au résultat de l'évaluation de l'expression logique.

Exemple if else
if (condition)
    alert("La condition est vrai");
    else
        alert("la condition est fausse");
.
.
.
if (condition)
{
    alert("La condition est vraie");
    alert("... je le confirme");
}
    else
    {
        alert("la condition est fausse");
        alert("... je le confirme");
    }

Cet opérateur est remarquable par sa concision et peut se substituer à la structure if… else. Il est expliqué en détails sur la page précédente.

Parfois, il permet d'économiser beaucoup de code. En théorie, presque toute structure if... else peut être remplacée par cet opérateur, du moment qu'elle ne contient pas de déclaration. En pratique, il vaut mieux le réserver à des cas simples.

Le mot réservé switch permet en conjonction avec case de mettre en place un sélecteur de cas d'une grande souplesse.
Cette structure remplace avantageusement une structure équivalente construite à partir de if else et if else imbriqués.
Le mécanisme de test ne fait pas appel à une expression logique, mais à une comparaison d'une variable de type scalaire avec des valeurs du même type.
Contrairement au langage C, qui nécessite que les valeurs de comparaison soient des constantes littérales, JavaScript, interprété, autorise l'usage de variables.
La structure switch case ne pourrait pas fonctionner correctement sans break. En effet, et cela est déconcertant au début, quand une condition case est vérifiée, l'interpréteur n'effectue plus de test et exécute tout ce qu'il trouve jusqu'à la fin en passant par dessus les case rencontrés.
Enfin, le mot réservé default couvre les cas différents de ceux traités par les case.

switch exemple 1
switch(ma_var)
{
var egal_deux = 2;
     case 1 :
          alert("Ma variable vaut 1");
     break;
     case egal_deux :
          alert("Ma variable vaut 2");
     break;       
     default : alert("Ma variable vaut autre chose que 1 ou 2");
}

On remarque les break systématiques dans ce cas.
D'autre part, on illustre la possibilité de fournir des variables à case, ce qui n'est pas possible en langage C. Deuxième exemple : Nous allons regrouper plusieurs cas, et déclencher plusieurs exécutions d'instructions pour certaines valeurs.

switch exemple 2
switch(ma_var)
{
     case 0:
          alert("Vraiment nulle, cette variable"); // Elle vaut zero
          break; 
     case 1:
     case 3: alert("Ma variable vaut 1 ou 3");  // Et on continue
     case 5:
          alert("Ma variable est impaire et comprise entre 1 et 5");
          break;
     case 2:
     case 4:
     case 6:
          alert("Ma variable est paire et comprise entre 2 et 6");
          break;
     case 7:
          alert("Ma variable est égale à 7");
          break;          
     default: alert("Ma variable est négative ou supérieure à 7")
}

On remarquera l'utilisation des break pour regrouper des cas entre eux...

Contrôle d'itération (boucles)

modifier

JavaScript implémente les mêmes structures de contrôle d'itération que le langage c, à savoir les boucles for, while et do.
Avant de les examiner, nous allons regarder l'usage de continue et break appliqué aux boucles.

Utilisation de continue

modifier

Cette instruction permet à volonté de sauter des tours. L'exemple suivant saute le passage à zero d'une itération comprise entre -2 et 2.

Exemple de continue
for (var i=-2; i <= 2; i++)
{
     if (i==0)
         continue;
     alert(i);     // Affiche -2, puis -1, 1 et 2... mais pas le zero.
}

Cette fonctionnalité de continue est aussi applicable aux boucles while et do.

continue peut être suivi du nom d'une étiquette placée juste avant une boucle. Dans ce cas, l'exécution continue au niveau de cette boucle, pas de celle qui contient directement l'instruction continue.

Utilisation de break

modifier

Les boucle for, while et do autorisent l'usage de break pour sortir de l'itération.

Chacune de ces boucles possède une condition d'arrêt, mais parfois il peut être souhaitable de sortir de la boucle pour d'autres raisons (en cas d'erreur, si on a trouvé ce qu'on cherchait avant la fin d'une recherche, si l'utilisateur a décidé d'annuler une longue opération…). Par défaut, break termine immédiatement la boucle dont il fait partie et le script continue après cette boucle.

De même que continue, break peut être suivi du nom d'une étiquette. Dans ce cas, l'exécution continue après la structure désignée par l'étiquette, pas après la boucle qui contient directement l'instruction break.

 

Quand on utilise la boucle jQuery .each(), elle exécute une fonction, donc il faut remplacer "break" par "return false".

Exemple pour sélectionner une option d'un menu déroulant :

$(document).ready(function(){
    $("#liste_deroulante > option").each(function() {
        if ($(this).val() == "valeur à sélectionner") {
            $(this).attr('selected','selected');
            return false;
        }
    });
});

Étiquettes

modifier

Une étiquette est un identifiant suivi de ':' (deux points). On peut la placer avant une instruction ou une structure de contrôle.

Il n'y a pas d'instruction goto en JavaScript. Les étiquettes servent exclusivement à affiner l'utilisation de break et continue (voir plus haut).

str = "Liste des objets :\n"
annuler = false

parcoursListe : for(i in liste)
{
   if(!liste.hasOwnProperty(i))
      continue    // passe à l'itération suivante dans cette boucle
   str+="\n• L'élément «"+i+"» de la liste contient :\n"
   if(annuler)
   {
      str+="\nopération annulée."
      break    // reprend l'exécution immédiatement après cette boucle
   }
   parcoursProps : for(j in liste[i])
   {
      if(!liste[i].hasOwnProperty(j))
         continue    // passe à l'itération suivante dans cette boucle
      if(annuler)
      {
         str+="\nopération annulée."
         break parcoursListe    // reprend l'exécution immédiatement après la boucle extérieure
      }
      str+="- "+j+" = "+liste[i][j]+"\n"
   } 
}

Description

modifier

La structure for permet d'effectuer plusieurs fois une ligne d'instructions ou un bloc d'instructions.
Les modalités d'exécution de l'itération sont indiquées entre les parenthèses précédant le mot réservé for. L'instruction ou le bloc à exécuter se situent après.
Syntaxe:

for (modalités) action;
ou
for (modalités){action1; action2;}


Par modalités, nous regroupons en fait trois choses distinctes qui sont:

  • l'initialisation
  • La condition pour exécuter la boucle
  • Les changements à effectuer à chaque tour (généralement une incrémentation ou décrémentation).

Ces trois instructions sont séparées par des points-virgule et placées entre parenthèses après le mot réservé for.
Généralement, ces trois instructions s'appliquent à une variable chargée de contrôler l'itération, et qu'on nomme avec la lettre i.

Boucle croissante

modifier

L'exemple le plus simple est le suivant :

Exemple for
for (i = 0; i < 5; i++)
{
     alert(i);     // Affiche 0, puis 1, puis 2, puis 3, puis 4
}

Dans cet exemple, nous avons initialisé la variable i à 0, défini la condition pour exécuter la boucle (répéter tant que i est strictement inférieur à 5) et défini le changement à effectuer à chaque tour (incrémenter i).
Une fois assimilé le fonctionnement, on imagine aisément toutes les possibilités.
D'abord, on peut initialiser i avec la valeur de son choix. Commencer avec 1, ou un nombre négatif.
Ensuite, on est libre de l'expression de la condition : strictement inférieur à 5, inférieur ou égal à 5 (<=) à condition devienne fausse à un moment donné, pour sortir.

Boucle à paliers

modifier

On n'est pas tenu exclusivement d'incrémenter i. On peut modifier la valeur par pas de 2.

Autre exemple for
for (i = 4; i <= 10; i += 2)
     alert(i + "est un nombre pair compris entre 4 et 10); // affiche 4, puis 6, 8 et 10

Boucle décroissante

modifier

De la même manière, une boucle peut être décroissante :

Exemple for, boucle décroissante
for (i = 5; i >= 0; i--)
     alert(i); // affiche 5, puis 4, 3, 2, 1 et 0

État en sortie de boucle

modifier

En sortie de boucle, i contient la valeur résultante des modifications. Pour le dernier exemple, c'est -1.

Boucle de parcours

modifier

Grâce à l'opérateur in il est possible d'utiliser une forme spéciale de la boucle for pour parcourir un tableau ou une table associative (clé -> valeur) par ses indices/clés :

Exemple for, parcours d'un tableau
var tableau = [ "une", "boucle for", "spéciale" ];
for (var i in tableau)
     alert(tableau[i]); // affiche successivement tous les éléments du tableau
     // i valant successivement : 0, 1, 2
Exemple for, parcours d'une table associative
var table = { "yes":"oui" , "no":"non" , "maybe":"peut-être" };
for (var i in table)
     alert(table[i]); // affiche successivement "oui", "non", "peut-être"
     // i valant successivement : "yes", "no", "maybe"
Clés et valeurs
modifier
Pour avoir les clés en plus des valeurs
var table = { "yes":"oui" , "no":"non" };
for (const [key, value] of Object.entries(table)) {
     console.log(key, value);
}

ou :

var table = { "yes":"oui" , "no":"non" };
table.forEach(function callback(key, value) {
  console.log(`${key}: ${value}`);
});

Éviter les pièges :

modifier
Boucle infinie
modifier

Il est possible, par inattention, de programmer une boucle infinie. Cela se produit quand la condition de boucle reste vraie malgré la modification de la variable.

for (i=0; i >= 0; i++)

L'incrémentation de i ne changera pas le fait que la variable est supérieure ou égale à zéro...

Variable modifiée
modifier

La structure for s'appuie sur une variable pour piloter le déroulement de la boucle. Seulement, elle ne rend pas la variable comme elle l'a reçue. Elle la modifie complètement. Pour éviter de modifier une variable par erreur, il est judicieux d'utiliser le mot réservé var pour déclarer une variable locale à la boucle :

for (var i=0; ....

La structure while conditionne l'exécution répétée d'une instruction ou d'un bloc d'instructions au test d'une expression logique.

while (condition)
     action;

ou

while (condition)
{
     action1;
     action2;
}

Pour qu'il soit possible de sortir de la boucle, il faut que les instructions modifient à terme la condition pour la rendre fausse.

Exemple while
var i = 0; // Initialiser i
while (i<5) // Tant que i est strictement inférieur à cinq
   i++;        // ... l'incrémenter.

En langage c, la boucle while peut-être volontairement infinie : while(true) toujours vrai, mais en JavaScript, le navigateur ne l'acceptera probablement pas.

La structure do permet d'exécuter une instruction ou un bloc d'instructions et de répéter cette action tant qu'une expression logique surveillée par while est vraie.

do
     action
     while (condition)
Exemple do
var i = 0;
do
{
     i++
}
     while(i < 5);