II. Les bases du JavaScript : valeurs, variables et structures de contrôle▲
Dans le monde des ordinateurs, seules les données existent. Ce qui n'est pas une donnée n'existe pas. Bien que toute donnée soit en essence seulement une séquence de bits(3), et en cela fondamentalement similaire, chaque morceau de donnée joue un rôle qui lui est propre. Dans le système JavaScript, la plupart de ces données sont soigneusement réparties entre des choses appelées valeurs. Chaque valeur a un type qui détermine le rôle qu'elle peut jouer. Il y a six types de valeurs de base : les nombres, les chaînes de caractères, les booléens, les objets, les fonctions et undefined pour représenter les valeurs indéfinies.
Pour créer une valeur, on doit seulement invoquer son nom. C'est très pratique. Vous n'avez pas à rassembler du matériel de construction pour vos valeurs, ou payer pour elles, il vous suffit d'en appeler une et hop, vous l'avez. Elles ne sont pas créées à partir de rien, évidemment. Chaque valeur doit être stockée quelque part, et si vous voulez en utiliser un grand nombre en même temps la mémoire de l'ordinateur pourrait venir à manquer. Heureusement, ce problème ne se présente que si vous devez les utiliser simultanément. Dès que vous n'utiliserez plus une valeur, elle se dissipera en ne laissant que quelques bits derrière elle. Ces bits sont recyclés pour fabriquer la génération suivante de valeurs.
Les valeurs de type nombre sont, comme vous l'aurez peut-être déduit, des valeurs numériques. Elles sont écrites de la manière dont sont habituellement écrits les nombres :
144
Saisissez cela dans la console et la même chose est affichée dans la fenêtre de sortie. Le texte que vous avez saisi a donné naissance à une valeur numérique ; la console a pris ce nombre et l'a affiché de nouveau à l'écran. Dans ce cas, c'était assez inutile, mais nous produirons bientôt des valeurs de manières moins directes et il pourra être utile de « les essayer » dans la console pour voir ce qu'elles produisent.
Voilà à quoi ressemble 144 écrit sous forme de bits(4):
0100000001100010000000000000000000000000000000000000000000000000
Le nombre précédent a 64 bits. C'est le cas de tous les nombres en JavaScript. Cela a une répercussion importante : il y a une quantité limitée de nombres pouvant être exprimés. Avec une décimale à trois chiffres, seuls les nombres de 0 à 999 peuvent être écrits, soit 103= 1000 nombres différents. Avec 64 chiffres binaires, on peut écrire 264 nombres différents. Cela en fait beaucoup, plus de 1019 (un 1 suivi de dix-neuf zéros).
Tous les nombres inférieurs à 1019 ne tiennent cependant pas dans un nombre JavaScript. D'une part, il y a aussi les nombres négatifs, ce qui oblige à utiliser un des bits pour stocker le signe du nombre. Mais ensuite, la représentation des nombres décimaux est un problème encore plus important. Pour permettre celle-ci, 11 bits sont utilisés pour stocker la position de la virgule au sein du nombre.
Il nous reste donc 52 bits(5). Tout nombre entier inférieur à 252, ce qui correspond à plus de 1015, sera contenu sans risque dans un nombre JavaScript. Dans la plupart des cas, les nombres que nous utilisons restent bien en deçà, nous n'avons donc absolument pas besoin de nous préoccuper des bits, ce qui nous arrange. Je n'ai rien de particulier contre les bits, mais vous avez besoin de beaucoup d'entre eux pour pouvoir faire quoi que ce soit. Si possible, il est donc plus agréable de travailler avec des entités plus grosses.
Les nombres décimaux s'écrivent en utilisant un point.
9
.
81
Pour les nombres très grands ou très petits, il est possible d'utiliser la notation « scientifique », en ajoutant un e suivi de l'exposant du nombre :
2
.
998e8
Ce qui donne 2.998 * 108 = 299800000.
Les opérations avec des nombres sans virgule (aussi appelés nombres entiers) tenant en 52 bits sont garanties d'être toujours précises. Malheureusement, les opérations avec des nombres fractionnaires ne le sont généralement pas. Tout comme π (pi) qui ne peut être exprimé de manière précise par un nombre fini de chiffres à décimales, beaucoup de nombres perdent en précision lorsqu'on ne dispose que de 64 bits pour les stocker. C'est dommage, mais cela ne crée de problèmes pratiques que dans des situations très spécifiques. Le plus important est d'en être conscient et de considérer les nombres fractionnaires décimaux comme des approximations et non des valeurs précises.
On utilise les nombres principalement en arithmétique. Les opérations arithmétiques, comme l'addition ou la multiplication prennent deux valeurs de type number pour créer un nouveau nombre. Voici ce que cela donne en JavaScript :
100
+
4
*
11
Les symboles + et * sont appelés des opérateurs. Le premier correspond à l'addition et le second à la multiplication. Placer un opérateur entre deux valeurs le fera s'appliquer à ces deux valeurs et produire une nouvelle valeur.
L'exemple veut-il dire « ajouter 4 et 100 puis multiplier le résultat par 11 », ou la multiplication est-elle effectuée avant l'addition ? Comme vous l'avez probablement deviné, la multiplication a lieu en premier. Mais comme en mathématiques, cela peut être modifié en entourant l'addition de parenthèses :
(
100
+
4
) *
11
Pour la soustraction, il y a l'opérateur -, et la division peut être effectuée avec /. Lorsque des opérateurs apparaissent ensemble sans parenthèses, l'ordre dans lequel ils sont appliqués est déterminé par la priorité des opérateurs. Le premier exemple montre que la multiplication a une priorité plus forte que l'addition. La division et la multiplication viennent toujours avant la soustraction et l'addition. Lorsque plusieurs opérateurs ayant la même priorité se suivent (1 - 1 + 1) ils sont appliqués de gauche à droite.
Essayez de trouver la valeur que produit cette opération, puis exécutez-la en console pour voir si vous aviez raison...
115
*
4
-
4
+
88
/
2
Vous ne devriez pas avoir à vous inquiéter de ces règles de priorité. En cas de doute, ajoutez simplement des parenthèses.
Il y a encore un opérateur arithmétique qui vous est sûrement moins familier. Le symbole % est utilisé pour représenter l'opération modulo. X modulo Y est le reste de la division de X par Y. Par exemple 314 % 100 vaut 14, 10 % 3 vaut 1 et 144 % 12 vaut 0. Modulo a le même ordre de priorité que la multiplication et la division.
Le type de données suivant est la chaîne de caractères (string). Son utilisation n'est pas aussi évidente à deviner d'après son nom que pour « number », mais elle remplit également un rôle très basique. Les chaînes de caractères sont utilisées pour représenter du texte, le nom est censé venir du fait qu'il enchaîne un groupe de caractères ensemble. Les chaînes de caractères sont écrites en insérant leur contenu entre des guillemets :
"Colmater mon bateau avec du chewing-gum."
On peut mettre pratiquement tout ce qu'on veut entre des guillemets et le JavaScript fera la conversion en une valeur de type string. Mais pour certains caractères c'est un peu tordu. Vous pouvez imaginer à quel point il est délicat de mettre des guillemets entre guillemets. Les sauts de lignes, comme vous en faites en appuyant sur Entrée, ne peuvent pas non plus être mis entre guillemets, la chaîne doit tenir sur une seule ligne.
Pour mettre de tels caractères dans une chaîne, on emploie l'astuce suivante : à chaque fois qu'on trouve un antislash (« \ ») dans un texte entre guillemets, cela signifie que le caractère qui le suit a une signification particulière. Un guillemet qui est précédé d'un antislash n'achèvera pas la chaîne mais en fera partie. Quand le caractère « n » se trouve derrière l'antislash, il est interprété comme un saut de ligne. De même, un « t » derrière un antislash signifie un caractère de tabulation(6).
"Voici une première ligne
\n
Et maintenant la seconde"
Il existe bien entendu des cas où vous voudrez que l'antislash dans une chaîne soit juste un antislash et pas un caractère d'échappement. Si deux antislashs se succèdent, ils vont se combiner et seul l'un d'eux sera conservé dans la chaîne résultante :
"Un caractère de saut de ligne est écrit ainsi
\"\\
n
\"
."
Les chaînes ne peuvent être divisées, multipliées ou soustraites. L'opérateur + peut être utilisé avec des chaînes. Il n'ajoute rien au sens mathématique mais concatène les chaînes, il les colle ensemble.
"con"
+
"cat"
+
"é"
+
"ner"
Il existe bien d'autres outils pour manipuler des chaînes de caractères, nous les exposerons par la suite.
Tous les opérateurs ne sont pas des symboles. Certains sont écrits sous forme de mots. Par exemple l'opérateur typeof qui renvoie une chaîne de caractères spécifiant le type d'une valeur.
typeof 4
.
5
Les autres opérateurs que nous avons vus opèrent toujours sur deux valeurs, typeof sur une seule. Les opérateurs qui utilisent deux valeurs sont appelés des opérateurs binaires alors que ceux qui n'en utilisent qu'une sont des opérateurs unaires. Le signe moins peut être utilisé aussi bien comme un opérateur binaire que comme un unaire :
- (
10
-
2
)
Il existe enfin des valeurs de type booléen. Il n'en existe que deux : true pour vrai et false pour faux. Voici un moyen de produire une valeur true :
3
>
2
Et on peut produire false comme ceci :
3
<
2
J'espère que vous connaissiez déjà les signes > et <. Ils signifient, respectivement, « plus grand que » et « plus petit que ». Ce sont des opérateurs binaires et le résultat de leur application est une valeur booléenne qui indique dans ce cas si l'expression est vérifiée ou non.
On peut comparer des chaînes de la même façon :
"Aardvark"
<
"Zoroaster"
Le classement des chaînes suit plus ou moins l'ordre alphabétique. Plus ou moins parce que... les lettres majuscules sont toujours « plus petites que » les minuscules, donc "Z" < "a" (« Z » en majuscule, « a » en minuscule) vaut true et les caractères non alphabétiques (« ! », « @ », etc.) sont également inclus dans ce classement. Le véritable principe sur lequel repose la comparaison est le standard Unicode. Ce dernier assigne un nombre à potentiellement tout caractère dont on peut avoir besoin, y compris les caractères spéciaux de langues comme le grec, l'arabe, le japonais, le tamoul, et ainsi de suite. Disposer de tels nombres est bien pratique pour stocker des chaînes de caractères dans un ordinateur - : vous pouvez les représenter comme une série de nombres. En comparant les chaînes, le JavaScript se contente de comparer les nombres associés aux caractères dans la chaîne, de gauche à droite.
Voici d'autres opérateurs du même genre : >= (« supérieur ou égal à »), <=_ (« inférieur ou égal à »), == (« égal à »), et != (« n'est pas égal à »).
"Itchy"
!=
"Scratchy"
5e2
==
500
Il existe également des opérations très utiles qui peuvent être appliquées aux valeurs booléennes elles-mêmes. JavaScript prend en charge trois opérateurs logiques : et, ou et non, que l'on peut utiliser pour des opérations logiques sur les booléens.
L'opérateur && représente le et logique. C'est un opérateur binaire dont le résultat est true seulement si les deux valeurs qu'on lui donne sont true.
|| est le ou logique, qui vaut true si l'une ou l'autre des valeurs qu'on lui attribue est true :
Non s'écrit avec un point d'exclamation : !, c'est un opérateur unaire qui inverse la valeur qu'on lui attribue, !true devient false et !false signifie true.
((
4
>=
6
) || (
"herbe"
!=
"verte"
)) &&
!(((
12
*
2
) ==
144
) &&
true)
Est-ce vrai (true) ? Pour une meilleure lisibilité, on peut se séparer d'un grand nombre de parenthèses inutiles ici. Cette version, plus simple, signifie la même chose :
(
4
>=
6
||
"herbe"
!=
"verte"
) &&
!(
12
*
2
==
144
&&
true)
Oui, l'expression vaut bien true. Vous pouvez la décomposer étape par étape comme ceci :
J'espère que vous avez remarqué que "herbe" != "verte" est true. L'herbe est peut-être verte, mais elle n'est pas égale à "verte".
Il n'est pas toujours évident de savoir si des parenthèses sont nécessaires. En pratique, on peut généralement s'en sortir en sachant que parmi tous les opérateurs rencontrés, || a la priorité la plus basse, viennent ensuite, dans l'ordre, && puis les opérateurs de comparaisons (>, ==, et cetera) et enfin tout le reste. Ceci a été déterminé de telle sorte que, dans les cas simples, on ne doive utiliser les parenthèses que si elles sont strictement nécessaires.
Les exemples rencontrés jusqu'à présent utilisent le langage JavaScript de la même façon que l'on se sert d'une calculatrice de poche. Utiliser des valeurs et leur appliquer des opérateurs pour obtenir d'autres valeurs. Créer de telles valeurs est une partie essentielle de chaque programme JavaScript, mais ce n'en est qu'une partie. Un bout de code qui produit une valeur s'appelle une expression. Chaque valeur écrite directement (telle que 22 ou "psychanalyse") est une expression. Une expression entre parenthèses est également une expression. Un opérateur binaire appliqué à deux expressions, ou un opérateur unaire appliqué à une seule expression est également une expression.
Il existe quelques autres moyens de construire des expressions, qui seront dévoilés lorsque le moment sera venu.
Il existe une unité plus grande que l'expression. On l'appelle instruction. Un programme est une suite d'instructions. La plupart des instructions se terminent par un point-virgule (;). La forme la plus simple d'une instruction est une expression avec un point-virgule après. Voici un programme :
1
;
!
false;
Ce programme est inutile. Une expression peut se contenter de produire une valeur, mais une instruction ne vaudra quelque chose que si elle change un peu le monde. Elle peut imprimer quelque chose à l'écran - ce qui compte comme un changement du monde - ou elle peut modifier l'état interne du programme de telle sorte que cela affecte les instructions qui suivent. Ces modifications sont appelées « effets de bord ». Les instructions de l'exemple ci-dessus ne renvoient que les valeurs 1 et true puis les jettent au récupérateur de bits(7). Ceci ne laisse aucune trace dans ce monde et ça n'a aucun effet de bord.
Comment un programme conserve-t-il un état interne ? Comment se rappelle-t-il les choses ? Nous avons vu de quelle façon créer de nouvelles valeurs à partir de vieilles valeurs, mais cela ne modifie pas les valeurs de celles-ci, et la nouvelle valeur doit être utilisée immédiatement ou elle disparaîtra. Pour « attraper » et conserver des valeurs, JavaScript fournit un mécanisme appelé la variable.
var attrape =
5
*
5
;
Une variable possède toujours un nom et elle peut pointer vers une valeur et la conserver. L'instruction ci-dessus crée une variable appelée attrape et l'utilise pour conserver le nombre produit par la multiplication de 5 par 5.
Après avoir exécuté le programme ci-dessus, vous pouvez entrer le mot attrape dans la console et cela ressortira la valeur 25 à votre place. Le nom d'une variable est utilisé pour récupérer sa valeur. attrape + 1 fonctionne également. Un nom de variable peut être utilisé comme expression et ainsi faire partie de plus grandes expressions.
Le mot-clé var est utilisé pour créer des variables. Le nom de la variable suit var. Les noms de variable peuvent être à peu près n'importe quel mot, mais ils ne peuvent pas contenir d'espaces. Les chiffres peuvent faire partie du nom de variable, attrape22 est un nom valide, mais le nom ne doit pas commencer par un chiffre. Les caractères « $ » et « _ » peuvent être utilisés dans les noms comme s'ils étaient des lettres, ainsi $_$ est un nom de variable correct.
Si vous souhaitez que la nouvelle variable contienne tout de suite une valeur, comme c'est souvent le cas, vous pouvez utiliser l'opérateur = pour lui affecter la valeur d'une expression.
Si une variable pointe vers une valeur, cela ne veut pas dire qu'elles sont liées pour toujours. Vous pouvez utiliser l'opérateur = à tout moment sur une variable existante pour lui enlever sa valeur actuelle et la faire pointer sur une nouvelle valeur.
attrape =
4
*
4
;
Il est préférable d'imaginer les variables comme des tentacules plutôt que comme des boîtes. Elles ne contiennent pas de valeurs, elles s'en saisissent (et deux variables peuvent se référer à la même valeur). Seules les valeurs qui sont encore retenues par le programme lui sont accessibles. Quand vous avez besoin de vous souvenir de quelque chose, vous dressez un tentacule pour l'accrocher fermement ou enserrez une nouvelle valeur dans un tentacule existant : pour vous souvenir de la somme en dollars que Luigi vous doit encore, vous pouvez faire :
var detteLuigi =
140
;
Puis, à chaque fois que Luigi vous rembourse quelque chose, ce montant peut être décrémenté en allouant un nouveau nombre à la variable :
detteLuigi =
detteLuigi -
35
;
L'ensemble des variables et de leur valeur à un moment donné s'appelle l'environnement. Quand le programme se lance, cet environnement n'est pas vide. Il contient toujours un certain nombre de variables standards. Quand votre navigateur charge une nouvelle page, il crée un nouvel environnement et lui affecte les valeurs standards. Les variables créées et modifiées par les programmes d'une page sont conservées jusqu'à ce que le navigateur aille sur une nouvelle page.
Beaucoup de valeurs fournies par l'environnement standard sont de type « function » . Une fonction est une partie de programme contenue dans une valeur. Généralement, cette portion de programme fait quelque chose d'utile qui peut être invoqué en utilisant le nom défini pour la fonction. Dans un navigateur, la variable alert est reliée à une fonction qui ouvre une petite fenêtre avec un message. Elle s'utilise comme ceci :
alert
(
"Au fait, vos cheveux sont en feu."
);
Quand on exécute le code d'une fonction, on dit qu'on l'invoque ou qu'on l'appelle. La notation pour faire ça utilise des parenthèses. Chaque expression qui produit une valeur peut être invoquée en utilisant des parenthèses après son nom. La chaîne de caractères entre parenthèses est donnée à la fonction qui l'utilise en tant que texte pour l'afficher dans la fenêtre. Les valeurs données aux fonctions sont appelées paramètres ou arguments. alert en a juste besoin d'un, mais d'autres fonctions peuvent en vouloir plus.
Afficher une fenêtre de dialogue est un effet de bord. Beaucoup de fonctions sont utiles par leurs effets de bord. Une fonction peut aussi produire une valeur et dans ce cas elle n'a pas besoin de produire un effet de bord pour être utile. Par exemple, il existe une fonction Math.max, qui prend deux arguments et retourne le plus grand des deux :
alert
(
Math.max
(
2
,
4
));
Quand une fonction produit une valeur, on dit qu'elle la retourne. Parce qu'il n'y a que les expressions qui produisent des valeurs, les appels de fonctions peuvent être utilisés comme une partie d'une expression plus longue :
alert
(
Math.min
(
2
,
4
) +
100
);
Nous examinerons dans le chapitre 3 la façon de créer vos propres fonctions.
Comme l'a montré l'exemple précédent, alert peut être utile pour montrer le résultat de certaines expressions. Mais cliquer pour fermer toutes ces petites fenêtres peut devenir très vite énervant, donc à partir de maintenant nous allons plutôt utiliser une fonction similaire appelée print qui ne fait pas apparaître de fenêtre, mais écrit juste une valeur dans la zone de sortie de la console. print n'est pas une fonction standard du JavaScript, les navigateurs ne la fournissent pas, mais il est possible de l'utiliser dans ce livre, donc vous pouvez l'utiliser sur ces pages.
print
(
"N"
);
Une fonction similaire également disponible sur ces pages est show. Alors que print affichera son argument en texte brut, show essayera de l'afficher de la même manière qu'un programme le ferait. Ce qui signifie qu'il donnera plus d'information sur le type de la valeur. Par exemple, les chaînes de caractères garderont leurs guillemets, en utilisant show :
show
(
"N"
);
L'environnement standard fourni par les navigateurs contient quelques fonctions supplémentaires pour faire apparaître des fenêtres. Vous pouvez poser une question à l'utilisateur en lui demandant de répondre par « Oui » ou « Non », en utilisant la fonction prédéfinie confirm. Elle retourne un booléen, true si l'utilisateur choisit « Oui » et false si l'utilisateur choisit « Non ».
show
(
confirm
(
"Continuons-nous ?"
));
prompt peut être utilisé pour poser une question « ouverte ». Le premier argument est la question, le deuxième est le texte par défaut, proposé comme la réponse de l'utilisateur. Une ligne de texte peut alors être tapée dans la case de texte de la fenêtre et la fonction la retournera comme une chaîne de caractères.
show
(
prompt
(
"Dites-nous tout ce que vous savez."
,
"..."
));
Dans l'environnement, il est possible de donner une nouvelle valeur à presque toutes les variables. Ça peut être utile mais aussi dangereux. Si vous donnez la valeur 8 à print, vous ne pourrez plus jamais rien afficher. Heureusement, il y a un bouton « Réinitialiser » sur la console, qui réinitialise totalement l'environnement.
Des programmes d'une ligne ne sont pas très intéressants. Quand vous mettez plus d'une instruction dans un programme ces dernières sont, comme on peut s'en douter, exécutées une à la fois de haut en bas.
var leNombre =
Number(
prompt
(
"Choisissez un nombre"
,
""
));
print
(
"Votre nombre est la racine carrée de "
+
(
leNombre *
leNombre));
La fonction Number convertit une valeur en nombre, ce qui est nécessaire dans notre cas parce que le résultat de prompt est une chaîne de caractères. Il existe des fonctions similaires appelées String et Boolean qui convertissent des valeurs dans ces types.
Considérons un programme qui affiche tous les nombres pairs de 0 à 12. Une façon de le faire est d'écrire :
print
(
0
);
print
(
2
);
print
(
4
);
print
(
6
);
print
(
8
);
print
(
10
);
print
(
12
);
Ça marche mais lorsqu'on écrit un programme l'idée est de nous faire faire moins de travail et non pas plus. Si nous avions besoin des nombres pairs jusqu'à 100 cette méthode deviendrait tout simplement inexploitable. Nous avons besoin d'une manière de répéter une portion de code automatiquement.
var nombreCourant =
0
;
while (
nombreCourant <=
12
) {
print
(
nombreCourant);
nombreCourant =
nombreCourant +
2
;
}
Vous avez sûrement vu dans l'introduction le mot while. Une instruction démarrant par while crée une boucle. Une boucle est une perturbation dans la séquence des instructions, il fera répéter plusieurs fois au programme une séquence de code. Dans notre cas le mot while est suivi par une expression entre parenthèses (les parenthèses étant obligatoires) qui détermine si la boucle continue à s'exécuter ou si elle doit s'arrêter. Aussi longtemps que la valeur booléenne produite par cette expression est true, le code à l'intérieur de la boucle est répété. Dès qu'elle devient false le programme se place à la fin de la boucle et reprend à la normale.
La variable nombreCourant montre la façon dont une variable peut suivre la progression d'un programme. À chaque fois que la boucle est répétée, la variable est incrémentée de 2 et à chaque début elle est comparée au nombre 12 pour décider si la boucle continue ou non.
La troisième partie d'une instruction while est une autre instruction. C'est le corps de la boucle qui contient les actions qui doivent se reproduire plusieurs fois. Si nous ne devions pas afficher les nombres le programme aurait pu être :
Ici nombreCourant = nombreCourant + 2; est l'instruction qui forme le corps de la boucle. Mais nous devons aussi afficher le nombre, donc la boucle sera constituée d'une instruction supplémentaire. Les accolades ({ et }) sont utilisées pour grouper des instructions dans des blocs. Pour le reste du code un bloc compte comme une seule et même instruction. Dans l'exemple précédent, ceci est utilisé pour inclure dans la boucle à la fois l'appel à la fonction print et l'instruction qui actualise la variable nombreCourant.
Utilisez cette technique pour écrire un programme qui calcule et affiche la valeur de 210 (2 à la puissance 10). Vous n'êtes bien sûr pas autorisé à tricher en écrivant juste 2 * 2 * ....
Si vous avez des problèmes avec ça, essayez de comparer avec l'exemple des nombres pairs. Le programme doit exécuter une action un certain nombre de fois. Pour cela, on peut utiliser une variable compteur avec une boucle while. À la place d'afficher le compteur, le programme doit multiplier quelque chose par deux. Ce quelque chose doit être une variable dans laquelle le résultat sera construit.
Ne vous inquiétez pas si vous ne voyez pas tout de suite comment cela peut fonctionner. Même si vous comprenez parfaitement tous les concepts de ce chapitre, il peut être dur de les appliquer à des problèmes concrets. Lire et écrire du code vous aidera à développer votre sensibilité pour ça. Donc, étudiez la solution, et essayez le prochain exercice.
var resultat =
1
;
var compteur =
0
;
while (
compteur <
10
) {
resultat =
resultat *
2
;
compteur =
compteur +
1
;
}
show
(
resultat);
Le compteur peut aussi commencer à 1 et être vérifié pour <= 10, mais pour des raisons que nous vous exposerons après il est préférable de commencer à compter depuis 0.
Évidemment vos solutions n'ont pas à être exactement identiques aux miennes. Elles doivent fonctionner. Et dans le cas où elles seraient très différentes, assurez-vous d'avoir compris la mienne.
Avec quelques petites modifications, la solution à l'exercice précédent peut être utilisée pour tracer un triangle. Et quand je dis « tracer un triangle », je veux dire « afficher du texte qui ressemble presque à un triangle quand on louche ».
Affichez dix lignes. Sur la première, mettez un « # ». Sur la deuxième en mettez-en deux, et ainsi de suite.
Comment avoir une chaîne composée de X « # » ? Une solution est de la construire avec une « boucle imbriquée », c'est-à-dire une boucle dans une boucle. Une méthode plus simple est de réutiliser la chaîne de la précédente itération, et d'y ajouter un caractère.
var ligne =
""
;
var compteur =
0
;
while (
compteur <
10
) {
ligne =
ligne +
"#"
;
print
(
ligne);
compteur =
compteur +
1
;
}
Vous remarquerez les espaces que j'ai mis devant certaines instructions. Ils ne sont pas nécessaires : l'ordinateur accepte très bien un programme sans ces espaces. En fait, même les retours à la ligne sont facultatifs.
Vous pouvez les écrire sur une seule longue ligne si cela vous fait plaisir. Le rôle de l'indentation dans les blocs est de construire la structure du code de manière plus claire et lisible pour les humains. Parce qu'on peut créer un nouveau bloc dans un autre et il peut alors devenir difficile de voir où un bloc finit et où un autre commence dans des parties complexes de code. Quand les lignes sont indentées, la forme visuelle du code correspond à la forme des blocs. Je préfère utiliser deux espaces pour chaque nouveau bloc, mais les goûts varient.
Le champ dans la console où vous pouvez taper des programmes ajoutera automatiquement ces espaces. Ça peut sembler pénible au début, mais quand vous écrirez beaucoup de code, vous verrez que c'est un gain de temps important. Appuyer sur la touche « tab » réindentera la ligne sur laquelle est le curseur.
Dans quelques cas, le JavaScript vous autorise à omettre le point-virgule en fin d'instruction. Dans d'autres cas, il faut le mettre sans quoi des choses étranges se produiront. Les règles définissant quand on peut les oublier sont complexes et particulières. Dans ce livre, je ne les enlèverai jamais et je vous conseille vivement de faire pareil pour vos propres programmes.
L'utilisation de while que nous avons vu plus haut suit toujours le même modèle. Premièrement une variable « compteur » est créée. Elle tracera la progression dans la boucle. L'instruction while contient une vérification, généralement pour voir si le compteur a atteint sa limite. Ensuite, à la fin du corps de la boucle, le compteur est mis à jour.
Beaucoup de boucles obéissent à ce schéma. C'est pour cette raison que le JavaScript, comme d'autres langages, fournit une forme plus courte et plus compréhensive :
Ce code est strictement équivalent à l'exemple précédent qui affichait les nombres pairs. La seule différence est que toutes les instructions liées à l'état de la boucle sont maintenant sur une seule ligne. Les parenthèses après le for doivent contenir deux points-virgules. La première partie initialise la boucle, généralement en définissant une variable. La deuxième est l'instruction qui vérifie l'état de la boucle. Et la dernière partie modifie l'état de la boucle. Dans beaucoup de cas, cette forme est plus claire et concise qu'une construction avec while.
J'ai utilisé une casse plutôt bizarre dans certains noms de variables. Comme vous ne pouvez pas utiliser d'espace dans ces noms - l'ordinateur les lirait comme deux variables distinctes - vos choix pour un nom composé de plusieurs mots sont plus ou moins limités aux solutions suivantes : petitpandaroux, petit_panda_roux, PetitPandaRoux ou petitPandaRoux. Le premier est difficile à lire. Personnellement, j'aime celui avec les tirets bas, bien que ce soit un peu pénible à taper. Toutefois, les fonctions JavaScript standards, et la plupart des programmeurs JavaScript, suivent la dernière syntaxe. Il n'est pas compliqué de s'habituer à ce genre de petites choses, alors je vais simplement suivre la majorité et mettre une majuscule à la première lettre de chaque mot excepté le premier.
Dans quelques cas, comme dans la fonction Number, la première lettre d'une variable est également une majuscule. Cela a été défini pour marquer cette fonction comme étant un constructeur. Ce qu'est un constructeur deviendra clair dans le chapitre 8. Pour l'instant, l'important est de ne pas se soucier de cet apparent manque de cohérence.
Notez que les noms ayant une signification spéciale tels que var, while et for ne peuvent pas être utilisés en tant que noms de variables. Ils sont appelés mots-clés. Il y a également un certain nombre de mots qui sont « réservés pour l'utilisation » dans de futures versions de JavaScript. Ceux-ci ne sont également officiellement pas autorisés à être utilisés comme noms de variables, bien que certains navigateurs les autorisent. La liste complète est assez longue :
abstract boolean break byte case catch char class const continue
debugger default delete do double else enum export extends false
final finally float for function goto if implements import in
instanceof int interface long native new null package private
protected public return short static super switch synchronized
this throw throws transient true try typeof var void volatile
while with
Ne vous souciez pas de les mémoriser pour le moment, mais souvenez-vous qu'ils peuvent être la cause d'un problème lorsque quelque chose ne fonctionne pas comme prévu. D'après mon expérience, char (pour stocker une chaîne d'un seul caractère) et class sont les noms d'utilisation incorrecte les plus communs.
Réécrivez les solutions des deux exercices précédents en utilisant for à la place de while.
var resultat =
1
;
for (
var compteur =
0
;
compteur <
10
;
compteur =
compteur +
1
)
resultat =
resultat *
2
;
show
(
compteur);
Notez que même s'il n'y a pas de bloc ouvert avec une « { », l'instruction dans la boucle est toujours indentée avec deux espaces pour bien spécifier son « appartenance » à la ligne du dessus.
var ligne =
""
;
for (
var compteur =
0
;
compteur <
10
;
compteur =
compteur +
1
) {
ligne =
ligne +
"#"
;
print
(
ligne);
}
Un programme a souvent besoin « d'actualiser » une variable avec une valeur basée sur sa valeur précédente. Par exemple compteur = compteur + 1. JavaScript fournit un raccourci pour cela : compteur += 1. Ça fonctionne également pour beaucoup d'autres opérateurs, par exemple resultat *= 2 pour doubler la valeur de resultat, ou compteur -= 1 pour compter à rebours.
Pour compteur += 1 et compteur -= 1, il existe même des versions abrégées : compteur++ et compteur--.
On dit que les boucles affectent le flux d'exécution d'un programme. Elles changent l'ordre dans lequel les instructions sont exécutées. Dans de nombreux cas, un autre type de flux est utile : les instructions de sauts.
Nous voulons afficher tous les nombres en dessous de 20 qui sont divisibles à la fois par 3 et par 4.
for (
var compteur =
0
;
compteur <
20
;
compteur++
) {
if (
compteur %
3
==
0
&&
compteur %
4
==
0
)
show
(
compteur);
}
Le mot-clé if n'est pas très différent du mot-clé while : il vérifie la condition qu'on lui donne (entre parenthèses) et exécute l'instruction suivante en fonction de cette condition. Mais il ne fait cela qu'une seule fois, donc l'instruction est exécutée zéro ou une fois.
L'astuce avec l'opérateur modulo (%) est une manière simple de tester si un nombre est divisible par un autre nombre. S'il l'est, le reste de leur division, qui est ce que modulo produit, est zéro.
Si nous avions voulu afficher tous les nombres en dessous de 20, mais en affichant entre parenthèses ceux n'étant pas divisibles par 4, nous aurions pu le faire de cette façon :
for (
var compteur =
0
;
compteur <
20
;
compteur++
) {
if (
compteur %
4
==
0
)
print
(
compteur);
if (
compteur %
4
!=
0
)
print
(
"("
+
compteur +
")"
);
}
Mais maintenant le programme doit déterminer si compteur est divisible par 4 deux fois. Le même effet peut être obtenu en ajoutant une partie else (« sinon ») après l'instruction if. L'instruction else est exécutée seulement lorsque la condition if est fausse.
for (
var compteur =
0
;
compteur <
20
;
compteur++
) {
if (
compteur %
4
==
0
)
print
(
compteur);
else
print
(
"("
+
compteur +
")"
);
}
Pour aller plus loin avec cet exemple trivial, nous voulons maintenant afficher ces mêmes nombres tout en leur ajoutant deux étoiles lorsqu'ils sont plus grands que 15, une étoile lorsqu'ils sont plus grands que 10 (mais pas plus grands que 15), et aucune étoile dans les autres cas.
for (
var compteur =
0
;
compteur <
20
;
compteur++
) {
if (
compteur >
15
)
print
(
compteur +
"**"
);
else if (
compteur >
10
)
print
(
compteur +
"*"
);
else
print
(
compteur);
}
Cela montre que vous pouvez enchaîner des instructions if. Dans ce cas, le programme regarde d'abord si compteur est plus grand que 15. Si c'est le cas, les deux étoiles sont affichées et les autres tests sont ignorés. Si ce n'est pas le cas, on continue à vérifier si la valeur est supérieure à 10. Et on n'arrive à la dernière instruction print que si compteur n'est pas supérieur à 10.
Écrivez un programme qui vous demandera, en utilisant prompt, quelle est la valeur de 2 + 2. Si la réponse est « 4 », utilisez alert pour afficher un message sympa. Si c'est « 3 » ou « 5 », affichez « Ça y était presque ! ». Dans les autres cas, n'hésitez pas à dire quelque chose de méchant.
var reponse =
prompt
(
"Hé vous ! Quelle est la valeur de 2 + 2 ?"
,
""
);
if (
reponse ==
"4"
)
alert
(
"Vous êtes un vrai génie !"
);
else if (
reponse ==
"3"
||
reponse ==
"5"
)
alert
(
"Ça y était presque !"
);
else
alert
(
"Vous êtes nul !"
);
Lorsqu'une boucle n'a pas systématiquement besoin d'aller jusqu'au bout de ses instructions, le mot-clé break peut être utile. Il permet de sortir de la boucle et d'exécuter les instructions suivantes. Ce programme trouve le premier nombre supérieur à 20 et divisible par 7 :
La structure for n'a pas de mécanisme qui vérifie quand terminer la boucle. Cela signifie qu'elle est dépendante de l'instruction break qui est à l'intérieur pour pouvoir s'arrêter. Le même programme aurait pu s'écrire aussi simplement...
Dans ce cas, le corps de la boucle est vide. Un point-virgule isolé peut être utilisé pour produire une instruction vide. Ici, le seul effet de la boucle est d'incrémenter la variable courant à la valeur voulue. Mais j'avais besoin d'un exemple utilisant break, donc prêtez également attention à la première version.
Ajoutez un while, et optionnellement un break, à votre solution du précédent exercice, afin qu'il continue à répéter la question jusqu'à ce qu'une réponse correcte soit donnée.
Notez que while, true... peuvent être utilisés pour créer une boucle qui ne s'arrêtera pas d'elle-même. C'est un peu ridicule, vous demandez au programme de boucler tant que true est true, mais c'est une astuce utile.
var reponse;
while (
true) {
reponse =
prompt
(
"Hé vous ! Quelle est la valeur de 2 + 2 ?"
,
""
);
if (
reponse ==
"4"
) {
alert
(
"Vous êtes un vrai génie !"
);
break;
}
else if (
reponse ==
"3"
||
reponse ==
"5"
) {
alert
(
"Ça y était presque !"
);
}
else {
alert
(
"Vous êtes nul !"
);
}
}
Parce que le corps du premier if a deux instructions, j'ai ajouté des accolades autour de tous les corps de if. C'est une question de goût. Avoir une chaîne if/else où certains corps sont des blocs et d'autres des instructions simples me semble un peu bancal. Mais je vous laisse vous faire votre propre opinion à ce propos.
Une autre solution, probablement meilleure mais sans break, est la suivante :
var valeur =
null;
while (
valeur !=
"4"
) {
valeur =
prompt
(
"Hé vous ! Quelle est la valeur de 2 + 2 ?"
,
""
);
if (
valeur ==
"4"
)
alert
(
"Vous êtes un vrai génie !"
);
else if (
valeur ==
"3"
||
valeur ==
"5"
)
alert
(
"Ça y était presque !"
);
else
alert
(
"Vous êtes nul !"
);
}
Dans la solution de l'exercice précédent il y a une instruction var reponse;. Elle crée une variable appelée reponse, mais ne lui donne pas de valeur. Que se passe-t-il alors lorsqu'on prend la valeur de cette variable ?
var variableMystere;
show
(
variableMystere);
En termes de tentacules, cette variable se termine dans les airs, elle ne s'accroche à rien. Quand vous demandez la valeur d'une variable vide, vous obtenez une réponse spéciale appelée undefined. Les fonctions qui ne retournent pas de valeur convenable, comme print et alert, retournent la valeur undefined.
show
(
alert
(
"Je suis un effet de bord."
));
Il y a aussi une valeur similaire, null, qui signifie que « cette variable est définie mais qu'elle n'a pas de valeur ». La différence entre undefined et null est principalement académique, et la majeure partie du temps sans intérêt. Dans la pratique, il est souvent nécessaire de vérifier si quelque chose possède une valeur. Dans ce cas, l'expression quelqueChose == undefined peut être utilisée, parce que même si ces deux valeurs ne sont pas strictement équivalentes, null == undefined retournera true.
Ceci nous amène vers un autre sujet un peu plus délicat...
show
(
false ==
0
);
show
(
""
==
0
);
show
(
"5"
==
5
);
Toutes ces expressions retournent true. Quand on compare des valeurs de différents types, JavaScript utilise un ensemble de règles complexes et déroutantes. Je ne vais pas essayer de les expliquer précisément. Dans beaucoup de cas, il essayera juste de convertir une des variables dans le type de l'autre variable. Cependant, quand null ou undefined apparaît, il produira true seulement si les deux sont null ou undefined.
Que faire si vous voulez tester si une variable se réfère à la valeur false ? La règle pour convertir des chaînes et des nombres en valeurs booléennes est que 0 et la chaîne vide sont considérés comme false, alors que toutes les autres valeurs comptent pour true. À cause de ça, l'expression variable == false est également true quand variable se réfère à 0 ou à "". Pour des cas comme celui-ci, où vous ne voulez aucune conversion automatique de types, il existe deux nouveaux opérateurs : === et !==. Le premier teste si une valeur est précisément égale à l'autre. Le deuxième teste si elles ne sont pas précisément égales.
Toutes ces instructions retournent false.
Les valeurs données comme conditions dans les instructions if, while, ou for ne doivent pas forcément être booléennes. Elles seront automatiquement converties en booléen avant d'être vérifiées. Cela signifie que le nombre 0, la chaîne vide "", null, undefined, et bien sûr false, compteront comme faux.
Le fait que toutes les autres valeurs soient converties en true permet dans beaucoup de situations d'omettre les comparaisons explicites. Si on sait qu'une variable contient une chaîne de caractères ou null, elle peut être utilisée dans une vérification de façon très simple...
var peutEtreNull =
null;
// ?code mystérieux qui pourrait affecter une chaîne à peutEtreNull?
if (
peutEtreNull)
print
(
"peutEtreNull possède une valeur"
);
...à l'exception du cas où ce code mystérieux affecterait la valeur "" à peutEtreNull. Une chaîne vide est fausse, donc rien ne sera affiché. Cette méthode peut donc être mauvaise, en fonction de ce que vous voulez faire. C'est donc souvent une bonne idée d'ajouter === null ou === false dans des cas comme celui-ci, pour éviter des erreurs subtiles. Ce commentaire s'applique aussi aux valeurs numériques qui peuvent être égales à 0.
La ligne qui parle du « code mystérieux » dans l'exemple précédent peut vous sembler un peu étrange. C'est souvent utile pour inclure du texte supplémentaire dans un programme. On l'utilise le plus souvent pour ajouter à un programme des explications en langage humain.
// La variable compteur, qui va être définie, commencera
// par la valeur 0, c'est-à-dire par zéro.
var compteur =
0
;
// Maintenant, nous allons créer une boucle.
while (
compteur <
100
/* compteur est inférieur à 100 */
)
/* À chaque fois que l'on boucle, nous incrémentons la valeur du compteur,
vraiment, on ajoute juste un. */
compteur++;
// Puis c'est fini.
Ce type de texte est appelé un commentaire. Les règles sont les suivantes : '/*' commence un commentaire qui se termine au prochain '*/'. '//' commence un autre type de commentaire qui finit à la fin de la ligne.
Comme vous pouvez le voir, même les programmes les plus simples peuvent être faits pour avoir l'air gros, laid et compliqué, simplement en ajoutant beaucoup de commentaires.
Il existe d'autres situations qui provoquent automatiquement une conversion de type. Si vous ajoutez une valeur non chaîne à une chaîne, cette valeur est automatiquement convertie en chaîne avant d'être concaténée. Si vous multipliez un nombre et une chaîne, JavaScript essaie de créer un nombre avec la chaîne.
show
(
"Apollo"
+
5
);
show
(
null +
"ifier"
);
show
(
"5"
*
5
);
show
(
"fraises"
*
5
);
La dernière instruction donne pour résultat NaN, qui est une valeur particulière. Elle signifie « Pas un nombre » (« Not a Number ») et elle est de type nombre (ce qui peut sembler légèrement paradoxal). Dans ce cas, cela signifie qu'une fraise n'est pas un nombre. Toutes les opérations arithmétiques sur la valeur NaN ont pour résultat NaN, c'est pourquoi en le multipliant par 5 comme dans cet exemple, cela donne toujours NaN. De plus, et c'est parfois assez perturbant, NaN == NaN est égal à false, vérifier si une valeur est NaN peut être fait avec la fonction isNaN. NaN est encore (c'est la dernière) une de ces valeurs qui renvoient false quand elles sont converties en booléen.
Ces conversions automatiques peuvent être très pratiques, mais elles sont aussi plutôt bizarres et sujettes à erreur. Même si + et * sont tous deux des opérateurs arithmétiques, ils se comportent de façons complètement différentes dans cet exemple. Dans mon propre code, j'utilise beaucoup + pour combiner les chaînes et les non-chaînes, mais notez bien qu'il ne faut pas utiliser * ni les autres opérateurs numériques sur des valeurs de chaînes. Convertir un nombre en chaîne est toujours possible et simple, mais convertir une chaîne en nombre peut très bien ne pas marcher du tout (voir la dernière ligne de l'exemple). Mais nous pouvons utiliser Number pour convertir explicitement la chaîne en nombre, en montrant bien que nous prenons le risque de nous retrouver devant une valeur NaN.
show
(
Number(
"5"
) *
5
);
Quand nous parlions des opérateurs booléens && et ||, je vous avais dit qu'ils produisent des valeurs booléennes. C'est en fait un peu trop simplifié. Si vous les appliquez sur des valeurs booléennes, ils retournent des booléens. Mais ils peuvent aussi s'appliquer à d'autres types de valeurs, et dans ces cas ils retournent un de leurs arguments.
En fait, ce que || fait réellement est ceci : il regarde la valeur de gauche en premier. Si la conversion en booléen produit true, il retourne cette valeur, sinon il retourne le membre de droite. Vérifiez par vous-même que cela fonctionne correctement avec des arguments booléens. Pourquoi agit-il comme cela ? Cela s'avère très pratique. Considérons l'exemple suivant :
var input =
prompt
(
"Quel est votre nom ?"
,
"Kilgore Trout"
);
print
(
"Bien le bonjour "
+ (
input ||
"cher ami"
));
Si l'utilisateur presse « Annuler » ou ferme la fenêtre de dialogue sans donner de nom, la variable input prendra la valeur null ou "". Ces deux donneront false en essayant de convertir en booléen. L'expression input || "cher ami" peut être lue dans ce cas comme « la valeur de la variable input, sinon la chaîne "cher ami" ». C'est une manière simple de fournir une valeur de secours.
L'opérateur && fonctionne sur le même principe mais dans l'autre sens. Quand la valeur à sa gauche est quelque chose qui donnera false en étant converti en booléen, il retournera cette valeur. Dans l'autre cas, il retournera la valeur à sa droite.
Une autre propriété de ces deux opérateurs est que l'expression de droite n'est évaluée que quand c'est nécessaire. Dans le cas true ||X, peu importe ce qu'est X, le résultat sera toujours true, donc X n'est jamais évalué, et s'il a des effets de bord, ils ne se produiront jamais. C'est la même chose pour false && X.