Copyright © 2017-2022 Yves MARCOUX; dernière modification de cette page : 2022-01-04.
SCI6373 Programmation documentaire
Yves MARCOUX - EBSI - Université de Montréal
? :
»Ce texte présente certains concepts de base du JavaScript (JS) :
Il propose une terminologie associée à ces concepts et illustre comment ceux-ci peuvent s’exprimer dans des expressions JS, lesquelles sont utilisées pour former des énoncés – ou instructions – JS, qui à leur tour, forment des programmes – ou scripts – JS.
Ce texte contient beaucoup d’exemples d’énoncés JS. Il est recommandé de les « essayer » en les faisant exécuter au fur et à mesure que vous les rencontrez dans le texte. Faire exécuter soi-même ces énoncés, observer les résultats obtenus et même formuler des variantes de son propre cru est la meilleure façon de bien comprendre les notions présentées.
Dans les environnements informatiques modernes, il y a de multiples façons de faire exécuter des énoncés JS. L’une d’elles est d’utiliser la composante d’un navigateur Web appelée console JavaScript. Puisque vous lisez ce texte sur le Web, nous recommandons d’utiliser la console du navigateur dans lequel vous lisez actuellement ce texte. Notez que cela exige que vous fassiez la lecture sur un ordinateur, et non sur une tablette ou un téléphone.
Voici les instructions pour configurer le navigateur Firefox pour un tel mode de lecture.
Visualisez la capsule vidéo qui démontre la procédure pour différents navigateurs, incluant Firefox. Vous noterez que le titre du document a changé depuis l’enregistrement de la capsule.
Procédure pour Firefox :
Dans la plupart des navigateurs (y compris Firefox), on peut aussi accéder à la console en faisant F12 puis en sélectionnant l’ongle Console.
Vous pouvez taper n’importe quel énoncé JS dans la console et le faire exécuter en appuyant sur Entrée. Ce qui est recommandé est d’essayer à la console tous les exemples donnés dans le texte. Le plus simple est de les copier-coller à partir de la version Web du texte (il se peut que vous ayez à « activer » le copier-coller dans la console; voir la capsule vidéo). Vous êtes aussi fortement encouragée à modifier les exemples et à observer l’effet obtenu et à formuler vos propres énoncés; c’est la meilleure façon d’apprendre.
Un énoncé JS est un peu comme une commande qui demande à l’interprète JS d’exécuter une certaine opération qui produit un résultat. Un énoncé JS est une « phrase » dans le langage JS, formée de mots, de signes de ponctuation et d’autres symboles.
Une session à la console JS d’un navigateur Web (la période entre l’ouverture et la fermeture de la console) est un dialogue entre l’utilisateur, qui inscrit des énoncés JS dans la console, et l’interprète JS intégré au navigateur, qui exécute ces énoncés et en affiche le résultat.
Typiquement, à la console JS, l’utilisateur inscrit un énoncé à la fois, puis
appuie sur la touche Entrée, après quoi l’interprète
exécute l’énoncé et affiche le résultat. Par exemple, si vous tapez à la console
(vous devriez l’essayer dès maintenant) : 2+2
suivi de la touche Entrée, vous obtenez ceci :
2+2
4
Nous affichons en vert le résultat retourné par l’interprète JS à la console en réponse à un énoncé. Les résultats d’interaction montrés dans le texte sont ceux qu’on obtient avec Firefox. Si vous utilisez un autre navigateur, ils pourraient être légèrement différents.
Les touches ↑ et ↓ du clavier permettent de naviguer dans l’historique des énoncés que l’on a soumis précédemment. Après qu’on ait rappelé un énoncé de l’historique, on peut le modifier avant de lancer de nouveau l’exécution en appuyant sur Entrée.
Si on appuie sur Entrée après avoir tapé un énoncé incomplet, l’interprète JS ne répond rien, mais attend qu’on le complète sur la ligne suivante et qu’on appuie de nouveau sur Entrée. Si on inscrit plus d’un énoncé sur la même ligne avant d’appuyer sur Entrée, l’interprète les exécute tous, mais n’affiche que le résultat du dernier. C’est aussi ce qui se produit lorsqu’on copie-colle plusieurs lignes d’un coup.
La console JS d’un navigateur Web est un outil de type « REPL », qui veut dire read-eval-print loop, dont la caractéristique est d’accepter un énoncé d’un langage de programmation (habituellement un seul énoncé), de l’exécuter et d’en afficher immédiatement le résultat, avant de retomber en attente d’un prochain énoncé à exécuter, un peu à la manière d’une calculette. Des outils REPL existent pour la plupart des langages de programmation, sous forme d’applications locales ou en ligne.
JavaScript (aussi appelé ECMAScript) est un des langages de programmation les plus répandus dans le monde. Intimement lié au HTML (en particulier HTML5), c’est le langage de programmation Web par excellence. Il est reconnu par tous les navigateurs Web et on le retrouve dans des millions de pages HTML sur le Web.
Mais le Web n’est qu’un des environnements où on retrouve le JS. On le retrouve également dans des documents PDF, formulaires de bases de données, applications Web côté serveur, dessins SVG, documents bureautiques, pour ne nommer que ceux-là.
Dans la spécification normalisée qui le décrit, JavaScript est défini indépendamment d’un environnement spécifique. Bien qu’il soit possible d’apprendre le langage de façon « désincarnée », sans référence à un environnement précis, il est beaucoup plus facile de le faire dans le cadre d’un environnement particulier.
Dans ce cours, l’environnement d’apprentissage choisi est celui des navigateurs Web. Un choix qui s’explique par l’utilité de connaître cet environnement et par le fait qu’il suffit d’un navigateur Web et d’un éditeur de textes pour passer à la pratique, deux outils omniprésents dans les systèmes informatiques courants.
Même si on peut faire exécuter les énoncés JS un par un à la console JS d’un navigateur Web, le JavaScript se présente habituellement sous la forme non pas d’un seul énoncé JS, mais de programmes (ou scripts), formés de plusieurs énoncés, inscrits l’un après l’autre dans un fichier texte.
Voici par exemple une page HTML avec un script JavaScript imbriqué, telle qu’elle pourrait se présenter dans un éditeur de textes typique, comme Notepad++ :
<html> <!-- Exemple typique de page HTML scriptée. --> <head> <title>Dites-moi vite bonjour !</title> </head> <body> <h1>Dites-moi vite bonjour !</h1> <form action="javascript:traiterFormulaire();"> <p>SVP, entrez votre nom : <input id="ctrlEntrée" type="text"> <input type="submit" value="OK"> </p> </form> <hr> <div id="sortie"></div> <script type="text/javascript"> // Initialisation de la page : let ctrlEntrée = document.getElementById("ctrlEntrée"); let sortie = document.getElementById("sortie"); let heureDébut = new Date(); ctrlEntrée.select(); function traiterFormulaire() { // Lecture des données : let nom = ctrlEntrée.value; let heureActuelle = new Date(); // Calculs : let temps = (heureActuelle - heureDébut) / 1000; let message = "Bonjour " + nom + " ! J’espère que vous allez bien.<br>"; message += `Vous avez pris ${temps} secondes pour répondre.`; // Affichage des résultats : sortie.innerHTML = message; // Préparation de la prochaine interaction : heureDébut = heureActuelle; ctrlEntrée.select(); }; </script> </body> </html>
Cet exemple est disponible ici, si jamais vous voulez l’essayer (facultatif).
On remarque tout de suite qu’une coloration syntaxique est appliquée par l’éditeur. Ces couleurs ne se retrouvent évidemment pas dans le fichier texte qu’est la page HTML, puisqu’un fichier texte ne contient que des caractères sans aucun attribut de présentation. Les couleurs sont ajoutées par l’éditeur de texte, exclusivement dans l’affichage présenté à l’utilisatrice, et simplement pour mettre en évidence les différentes constructions syntaxiques du ou des langages utilisés.
Ici, il y a deux langages utilisés : HTML et JS. Il y a donc deux schèmes de coloration syntaxique qui se « superposent ». Le JS est présenté sur fond bleu pâle, le reste correspond au HTML. De plus, chaque type de construction syntaxique de l’un ou l’autre des deux langages a ses propres couleur et formatage.
Si vous connaissez le HTML, vous reconnaissez les constructions habituelles que
sont les éléments <head>
, <title>
,
<body>
, etc. L’élément <script>
, qui est peut-être
nouveau pour vous, sert à « héberger » le JS de façon imbriquée dans la
page HTML. À l’intérieur de cet élément, ce n’est plus du HTML que l’on retrouve,
mais bien du code répondant aux règles syntaxiques du JS.
À part les commentaires, affichés en vert, ce code n’est rien d’autre qu’une suite
d’énoncés JS, chacun se terminant par un point-virgule ;
(qui peut
parfois être omis). Comme vous pouvez voir, chaque énoncé est placé sur sa propre
ligne de texte. Ce n’est pas obligatoire, mais c’est la pratique la plus répandue,
notamment parce qu’elle favorise la lisibilité du code.
Les énoncés JS sont donc les briques avec lesquelles on construit les programmes ou scripts JS, qui sont de véritables applications informatiques capables d’interagir avec des utilisatrices et d’accomplir des tâches utiles.
Expressions
Les expressions JS (ou simplement
« expressions ») sont un élément crucial de la composition des énoncés JS. Toute
expression JS (suivie facultativement d’un point-virgule ";
") est en
elle-même un énoncé et, sauf de très rares exceptions, un énoncé JS contient
toujours au moins une expression. La notion d’expression est donc fondamentale en JS
et c’est la raison pour laquelle le présent texte lui est entièrement consacré. Il
présente les formes les plus courantes d’expressions JS.
Le point-virgule en fin d’énoncé est presque toujours facultatif; aussi nous permettons-nous donc de l’omettre pour alléger nos exemples.
Le résultat d’une expression JS, donc ce qui est affiché par l’interprète
en réponse à l’expression, est toujours une valeur JS. Le concept de valeur
JS est très intuitif. Il s’agit d’un élément de donnée élémentaire et atomique
(traité comme un tout) pouvant être manipulé en JS. À part quelques valeurs « ésotériques » sur lesquelles nous aurons l’occasion de
revenir (comme notamment true
, false
,
undefined
, null
, NaN
et
Infinity
), une valeur JS ne peut être que l’une des trois
choses suivantes :
Une valeur qui n’est pas un pointeur à un objet est appelée une valeur simple. Une valeur simple est donc une valeur numérique, une chaîne de caractères ou une des valeurs « ésotériques ».
Un pointeur à un objet est comme une adresse numérique interne à l’interprète JS, que celui-ci peut utiliser pour accéder à un objet stocké en mémoire. Un objet n’est pas lui-même une valeur directement manipulable par un script. Un script ne peut manipuler directement que des pointeurs à des objets. Nous reviendrons plus loin sur les objets, mais nous concentrons pour le moment sur les valeurs simples.
Les constantes sont un premier type d’expressions JS, qui servent à dénoter des valeurs numériques ou caractères fixes. Les constantes numériques s’écrivent de la façon habituelle pour les nombres (avec le point comme séparateur décimal, et non la virgule), alors que les constantes caractères doivent être écrites entre guillemets (simples ou doubles). Les expressions suivantes (qui sont toutes des constantes) ont toutes comme valeur celle de la constante elle-même (essayez-les dans la console JS; vous pouvez les copier-coller à partir d’ici, puis appuyer sur Entrée) :
345
345
"Allô"
"Allô"
345.67
345.67
100.000
100
'Bonjour'
"Bonjour"
Le plus souvent, JS semble simplement recopier ce qui est tapé, mais il y a parfois
certaines différences. C’est que JS interprète véritablement la constante
comme une expression, dont il affiche la valeur résultante. Par exemple, vous pouvez
constater que, même si l’on spécifie trois zéros après le point dans
100.000
, JS nous retourne la valeur sous sa forme la plus simple,
sans les décimales. De même, la valeur caractère 'Bonjour'
nous est
retournée avec le guillemet double comme délimiteur.
Nous verrons plus tard dans le cours certaines particularités sur la façon d’écrire les constantes numériques et caractères, mais les formes ci-dessus nous suffisent pour le moment.
Le nom de chacune des valeurs « ésotériques » évoquées plus tôt, dont
true
, false
,
undefined
, null
,
NaN
et Infinity
, constitue
également une constante, et
donc une expression JS, dont la valeur est elle-même (nous ne montrons pas les
réponses de JS, puisqu’elles sont ici identiques aux expressions elles-mêmes, mais
nous vous encourageons à copier-coller et faire exécuter chacune dans la console
JS) :
true
false
undefined
NaN
Infinity
Nous reviendrons plus tard sur le rôle de certaines de ces valeurs ésotériques en JS.
Les quatre opérations arithmétiques communes +
, -
,
×
et ÷
peuvent être appliquées aux valeurs numériques.
La multiplication et la division, cependant, s’expriment avec les symboles
*
et /
respectivement, plutôt qu’avec les symboles
usuels. On parle d’« opération » pour désigner la fonction arithmétique elle-même,
et d’« opérateur » pour désigner le symbole graphique utilisé pour exprimer
l’opération dans le langage JS. On dira par exemple que l’opération de
multiplication est représentée par l’opérateur *
.
Les valeurs auxquelles une opération s’applique sont appelées les opérandes ou arguments. Les quatre opérations arithmétiques mentionnées s’appliquent toutes à deux arguments : un à gauche de l’opérateur et l’autre à droite.
Deux constantes jointes par un opérateur arithmétique mitoyen forment aussi une expression JS :
345+3
348
10 -12
-2
32* 0.5
16
25 / 0.25
100
80*1
80
Comme on peut constater, la présence d’espaces avant ou après l’opérateur ne change rien.
Concaténation de chaînes de caractères
L’opérateur + appliqué à des valeurs caractères effectue une opération différente de l’addition : la concaténation de chaînes de caractères, c’est-à-dire le « collage » des deux chaînes l’une à la suite de l’autre :
"ab" + "c"
"abc"
'4'+'ab'
"4ab"
"9" + '9'
"99"
"2 -"+"7"
"2 -7"
La constante ""
(tout comme ''
) dénote la chaîne vide, de
longueur nulle, ne contenant aucun caractère, mais qui est bel et bien une valeur
caractère. La chaîne vide se comporte dans la concaténation comme le 0
dans l’addition :
"abc" + ""
"abc"
'' + "ABC"
"ABC"
""+""
""
'' + ''
""
Une variable est un endroit de stockage où peut être enregistrée exactement une valeur JS, de façon à pouvoir être « rappelée » et réutilisée plus tard. Lorsque, comme programmeuse, on élabore un script qui consistera en une séquence de plusieurs instructions, il est extrêmement utile de pouvoir stocker en mémoire certaines valeurs de façon à pouvoir les réutiliser dans des étapes ultérieures : les variables servent exactement à cela.
Une variable est identifiée par un nom, qui lui est exclusif, et grâce auquel on pourra « rappeler » la valeur qu’elle contient. On crée une variable et on y place une valeur avec un énoncé de la forme :
nom
=
expression
par exemple :
x = 42
42
ou :
x = 84 * 0.5
42
On appelle ce genre d’expression assignation ou affectation de
variable. L’opérateur "=" est lui-même appelé
l’opérateur d’assignation ou d’affectation. On voit souvent les assignations précédées du mot-clé
var
ou let
. Ces mots-clés sont facultatifs. Leur
utilité sera discutée en classe.
Une assignation de variable comporte une expression après le "=", mais est aussi elle-même une expression. Comme expression, l’assignation retourne la valeur qui vient tout juste d’être stockée dans la variable; c’est d’ailleurs pour cette raison que JS nous affiche cette valeur en réponse à l’assignation.
Une fois qu’une variable a été définie – c’est-à-dire qu’une valeur lui a été assignée – on peut « rappeler » sa valeur en utilisant comme expression le nom de la variable :
x
42
Un nom de variable définie constitue donc une expression valide. Un nom de variable peut remplacer une constante dans les opérations de base que nous avons vues jusqu’ici :
x + 100
142
x+x
84
Bien sûr, ça marche aussi avec les valeurs de type caractère :
nom = "Jojo"
"Jojo"
"Bonjour "+nom
"Bonjour
Jojo"
Si on référence une variable qui n’a jamais été définie, on obtient un message d’erreur; par exemple :
Gertrude
Uncaught
ReferenceError: Gertrude is not defined
Les noms que l’on peut donner aux variables dans une assignation doivent être
composés de lettres (majuscules ou minuscules, avec ou sans accents ou autres signes
diacritiques), de chiffres, de caractères de soulignement "_
" et de
signes de dollar "$
". Ils doivent commencer par une lettre. Il n’y a
a priori pas de limite sur leur longueur. Voici des exemples
valides :
a
nombreDeLivres
leçon$2
Été_2020
La casse des lettres (majuscule vs minuscule) est significative :
A
ne désigne pas la même variable que a
. Notons que le
tiret "-
" n’est pas permis dans un nom de variable. Voici quelques
exemples incorrects :
212x
commence par un chiffre n#clients
le caractère #
est interditleçon 24
l’espace est interdite Été-2020
le tiret - est interdit
Certains noms spécifiques ne peuvent pas être utilisés comme noms de variable : les noms des « membres statutaires », de même que certains mots-clés réservés en JS. Les chances de tomber sur un tel nom par hasard sont faibles, mais il est de bonne pratique de vérifier qu’un nom envisagé est « libre » en le tapant comme expression à la console :
saison
Uncaught ReferenceError:
saison is not defined
Une des utilisations de base des variables est pour stocker les résultats intermédiaires de calculs, un peu comme la fonction « mémoire » des calculatrices; sauf qu’en JS, on a virtuellement une « infinité » de mémoires à notre disposition. Par exemple, supposons que vous achetez deux raquettes de tennis à 50$ et un boîte de balles à 12$, et que vous voulez connaître le coût total de votre achat, qui est sujet à une taxe de 15%. Voici une façon de décomposer le travail en une série d’expressions n’effectuant chacune qu’une seule opération :
coûtRaquettes = 50 * 2
100
coûtAvantTaxe = coûtRaquettes + 12
112
taxe = coûtAvantTaxe * 0.15
16.8
coûtTotal = coûtAvantTaxe + taxe
128.8
Évidemment, nous verrons sous peu qu’il est possible de combiner toutes ces opérations en une seule expression (en utilisant les parenthèses), mais l’exemple illustre un type important d’utilisation des variables.
Modification d’une variable
Si l’on affecte une nouvelle valeur à une variable déjà définie, l’ancienne valeur stockée disparaît; elle est simplement remplacée par la nouvelle valeur :
y = "cerf-volant"
"cerf-volant"
y = 40 + 2
42
y
42
Notons que, dans ce dernier exemple, la seconde assignation a
fait passer le type de valeur contenue dans y
de caractère à numérique.
Le fait que le contenu d’une variable puisse passer librement d’un type à un autre
est une des caractéristiques de JS qui en font un langage dynamique. Dans
un langage statique, les variables sont créées avec un type donné et toutes
les valeurs qu’on y place doivent être de ce type.
Auto-réassignation
Supposons que la variable y
soit définie ainsi :
y = 42
42
Un « pattern » que l’on retrouve très souvent en programmation est l’auto-réassignation, qui consiste en une assignation où la nouvelle valeur d’une variable est calculée à partir de son ancienne valeur :
y = y + 1
← auto-réassignation43
← nouvelle valeur
y = y + 1
← auto-réassignation44
← nouvelle valeur
L’effet des auto-réassignations ci-dessus était d’augmenter de 1 la valeur de la
variable y
. Nous verrons dans le cours que le JS possède certains
opérateurs spécifiquement pour effectuer certaines auto-réassignations courantes,
comme justement augmenter de 1 la valeur d’une variable numérique.
Comme nous avons dit plus haut, un nom de variable définie est en soi une expression valide, dont la valeur est celle stockée dans la variable. Nous avons aussi dit qu’un nom de variable peut remplacer une constante dans une des formes d’expression vues jusqu’ici. Cette règle est un cas particulier d’une règle plus générale, fondamentale en JS (et en programmation en général), permettant de construire des expressions qui expriment de façon très compacte des calculs complexes. C’est la règle du chaînage d’expressions. Elle tient en peu de mots, mais ses conséquences sont vastes :
Partout où une constante est permise dans une expression valide, on peut remplacer la présence de la constante par une autre expression valide, et on obtient encore une expression valide.
Voyons voir ce que cela signifie. Nous avons vu que 345 + 3
et 10 - 12
sont toutes deux des expressions valides. La règle du
chaînage d’expressions nous dit que les quatre constructions suivantes sont aussi
des expressions valides :
10 - 12 + 3
345 + 10 - 12
10 - 345 + 3
345 + 3 - 12
Supposons maintenant que prix
est défini par :
prix = 42
42
Nous savons déjà que les expressions suivantes sont possibles :
prix + 3
45
342 - prix
300
prix / 2
21
Jusqu’ici, rien de surprenant. Ce que la règle du chaînage nous permet de faire de nouveau, c’est de mettre plusieurs opérations dans la même expression :
prix / 2 + prix
63
On peut bien sûr mettre le résultat dans une autre variable, ou dans la même :
prixTotal = prix / 2 + prix
63
prix = prix / 2 + prix
63
Il n’y a aucune limite sur le nombre d’expressions que l’on peut « chaîner » par la règle du chaînage.
La possibilité de chaîner les expressions soulève la question de l’ordre d’exécution des opérations dans une expression qui comporte plusieurs opérateurs. En effet, est-ce que l’expression :
2 + 7 * 5
donne comme résultat 37
ou 45
? Si on exécute la
multiplication d’abord (comme on nous apprend à faire à l’école), elle donne
37
, alors que si on effectue l’addition d’abord, elle donne
45
. Laquelle des deux possibilités JS choisit-il ?
Un premier élément de réponse vient d’une autre règle importante pour la construction d’expressions, celle du parenthésage. Nous connaissons tous déjà cette règle, intuitivement :
Si on entoure de parenthèses
( )
une expression valide, on obtient encore une expression valide.
Si, par la règle du chaînage, une expression contient une partie parenthésée, cette dernière est évaluée avant la ou les opérations qui jouxtent les parenthèses. Ainsi, on peut imposer un ordre d’exécution en utilisant des parenthèses. On obtiendrait donc l’une des deux expressions suivantes :
(2 + 7) * 5
qui donne sans équivoque possible le résultat 45
, et :
2 + (7 * 5)
qui donne sans plus d’équivoque le résultat 37
.
Les parenthèses permettent donc d’imposer un ordre d’évaluation aux expressions chaînées en vertu de la règle du chaînage. Il n’y a aucune limite sur la « profondeur » avec laquelle on peut parenthéser les expressions.
Puisqu’on peut imposer l’ordre d’exécution des opérations dans une expression en
utilisant des parenthèses, on peut faire du JS toute sa vie sans jamais se
préoccuper de la priorité des différents opérateurs l’un par rapport à
l’autre. Cependant, JS attribue à chaque opérateur une priorité, dont il se sert
pour déterminer l’ordre d’exécution des opérations dans une expression complexe
en l’absence de parenthèses. Par exemple, les opérateurs *
et /
ont une priorité supérieure à celle des opérateurs +
et -
, ce qui correspond aux règles d’arithmétique usuelles.
Les règles sont :
Ainsi, dans l’expression :
2 + 7 * 5
la multiplication *
s’exécute en premier, car elle a un niveau de
priorité supérieur à celui de l’addition +
, donnant le résultat
37
.
Dans l’expression :
12 - 7 + 5
puisque +
et -
ont la même priorité, les deux opérations
sont effectuées de gauche à droite, et la soustraction est donc effectuée avant
l’addition. Le résultat est donc 10
, et non 0
, qui serait
le résultat de :
12 - (7 + 5)
La Table 22-10 dans Goodman et al. (pp. 434-5) donne toute l’information sur la priorité relative des opérateurs JS. Cependant…
Connaître la priorité de tous les opérateurs JS peut nous éviter de mettre des parenthèses inutiles dans une expression, mais ce n’est absolument pas une nécessité. En cas de doute sur la priorité relative de deux opérateurs, on peut bien sûr aller vérifier dans un ouvrage de référence sur le JS, mais on peut aussi simplement décider d’utiliser des parenthèses, quitte à ce qu’elles soient redondantes. Une paire de parenthèses de trop ne fait jamais de tort et peut même augmenter la lisibilité !
En fait, il n’y a que trois règles à retenir concernant la priorité des opérateurs JS :
À savoir par cœur concernant la priorité des opérateurs
*
et
/
ont la même priorité, laquelle est supérieure à celle
des opérateurs +
et -
, qui sont aussi entre eux
d’égale priorité.Les « opérateurs courants » incluent tous ceux vus dans le cadre du cours. Pour les besoins du cours, on peut donc considérer les opérateurs "=" et "." comment étant de priorité respectivement minimum et maximum parmi tous les opérateurs.
Ainsi :
v = 12 - 7 * 5
-23
est interprété comme :
v = (12 - (7 * 5))
et non comme :
v = ((12 - 7) * 5)
25
ni comme :
(v = 12) - (7 * 5)
-23
qui affiche pourtant le même résultat, mais qui n’a pas le même effet. Pour bien
comprendre ce que fait cette dernière expression, il faut se rappeler que
l’assignation, en tant qu’expression, retourne comme résultat la valeur
tout juste assignée. L’expression placerait donc la valeur 12 dans v
et
retournerait -23 comme résultat, alors que l’expression originelle place -23 comme
valeur dans v
, en plus de retourner cette même valeur (-23) comme
résultat.
Tel que mentionné plus tôt, il n’y a aucune limite sur la profondeur avec laquelle on peut chaîner et parenthéser les expressions. En pratique, la limite est plutôt la lisibilité de l’expression résultante. Cela étant dit, une expression d’une certaine complexité peut par ailleurs demeurer très lisible. Reprenons l’exemple ci-dessus de l’achat de deux raquettes de tennis à 50$ et d’un boîte de balles à 12$, où l’on veut connaître le coût total de l’achat, qui est sujet à une taxe de 15%. Le coût total peut facilement être calculé par une expression unique :
coûtTotal = (2 * 50 + 12) + (2 * 50 + 12) *
0.15
128.8
que l’on peut même simplifier (si l’on pense à la mise en évidence simple) :
coûtTotal = (2 * 50 + 12) * 1.15
128.79999999999998
Belle occasion de noter que, en JS comme partout en informatique, les calculs
numériques sont effectués avec une précision limitée et que des erreurs d’arrondi
peuvent toujours survenir, comme le démontre l’évaluation de l’expression
précédente. JS possède tout ce qu’il faut pour bien traiter ces cas, par exemple en
arrondissant le résultat d’une opération à deux chiffres après le point (en
utilisant par exemple Math.round()
ou .toFixed()
), mais ce
sujet dépasse la portée du présent texte.
Une expression imbriquée dans une autre expression plus longue est appelée sous-expression si l’ordre d’exécution des opérations fait en sorte que toutes les opérations dans l’expression imbriquée sont effectuées avant la ou les opérations qui la jouxtent dans l’expression plus longue. Par exemple, dans :
12 - 7 * 5
-23
l’expression 7 * 5
est une sous-expression, mais pas
12 - 7
.
Techniquement, 12
, 7
et 5
sont aussi toutes
les trois des sous-expressions, puisque (1) il s’agit bel et bien d’expressions
(rappelez-vous qu’une constante est en elle-même une expression) et (2) ne contenant
aucune opération, on peut dire que « toutes » les opérations contenues dans
l’expression sont effectuées avant celle(s) située(s) à gauche et/ou à droite de
l’expression.
Les sous-expressions de :
prixTotal = prix / 2 + 50
sont :
prixTotal
prix
2
50
prix / 2
prix / 2 + 50
Le cas de prixTotal
demande explications : comme elle est située à
gauche d’un opérateur d’assignation "=", elle est évaluée simplement comme nom de
variable, c’est-à-dire comme « endroit où placer la valeur de l’expression située à
droite du "=" ». En ce sens, elle est évaluée entièrement avant le "=" lui-même.
Techniquement, une sous-expression située à gauche d’un opérateur "=" est appelée « partie de gauche », ou en anglais « left-hand side » (LHS). Nous verrons dans le cours qu’une LHS peut être plus complexe qu’un simple nom de variable.
Arbres d’exécution
Nous verrons en classe un outil graphique permettant d’analyser des expressions complexes et de mettre en évidence l’ordre d’exécution des opérations : les arbres d’exécution.
Nous allons maintenant étendre un peu notre répertoire d’opérations JS. Plusieurs autres opérations s’ajouteront aussi en classe.
L’opérateur "-
" peut s’utiliser avec un seul argument, numérique, à
droite; il sert alors à inverser le signe de la valeur numérique :
-42
-42
-(-42)
42
- - 42
42
L’opérateur "+
" peut aussi s’utiliser de façon unaire, mais comme il
ne modifie pas la valeur numérique, sa présence ne sert à rien :
+42
42
Ces opérateurs unaires peuvent aussi s’utiliser avec une valeur caractère, à condition qu’elle puisse être convertie en nombre. La valeur est d’abord convertie en valeur numérique, puis l’opérateur est appliqué :
+"42"
42
-"42"
-42
Le "+" unaire est donc une façon simple de convertir une valeur caractère en valeur numérique, pourvu que la valeur caractère représente bien un nombre.
Si la valeur caractère ne représente pas un nombre, on obtient la valeur ésotérique
NaN
:
+"1.2.3"
NaN
-"abc"
NaN
Deux des valeurs ésotériques mentionnées au début de ce texte sont les valeurs
booléennes : true
et false
, représentées dans
les expressions par les constantes éponymes :
true
true
false
false
Plusieurs opérations JS retournent comme résultat une valeur booléenne. C’est le cas notamment des opérations de comparaison, qui servent à comparer deux valeurs JS.
Égalité (==
)
La plus simple des opérations de comparaison est celle d’égalité,
représentée par l’opérateur ==
(deux caractères
« =
», à ne pas confondre avec l’assignation, qui en utilise un
seul). L’opération d’égalité vérifie simplement si ses deux arguments sont égaux, et
retourne true
(vrai) si c’est le cas, et false
(faux)
autrement. Rappelons qu’un argument en JS est toujours une unique valeur
JS. Voici des exemples d’opération d’égalité :
42 == 42
true
42 == (15 + 27)
true
(40 == (40+2))
false
"abc" == 'abc'
true
'a' == 'a '
false
"a" == "A"
false
"a" == ('a' + "")
true
true == true
true
true == false
false
true == (40 == (40+2))
false
Autres opérations de comparaison
Les autres opérations de comparaison incluent :
Opérateur Opération de comparaison !=
N’est pas égal à >
Est plus grand que >=
Est plus grand que ou égal à <
Est plus petit que <=
Est plus petit que ou égal à
Toutes ces opérations, à l’instar de l’égalité ==
, peuvent travailler
avec des valeurs numériques, caractères et booléennes. Avec des valeurs caractères,
la comparaison s’effectue caractère par caractère et respecte la numérotation
Unicode des caractères. Les valeurs booléennes true
et
false
sont traitées comme les valeurs numériques 1
et
0
, respectivement.
Voici quelques exemples :
42 >= 42
true
42 > 42
false
-10 <= 0
true
"A" > 'a'
false
"A" < 'a'
true
"a " > 'a'
true
100 != 100.000
false
true != false
true
true > false
true
Ce dernier exemple équivaut à écrire : 1 > 0
, d’où le résultat
obtenu.
Les valeurs booléennes true
et false
sont aussi traitées
comme 1
et 0
par les opérateurs arithmétiques :
true+true
2
43-(4==(2+2))
42
42*("a"=="A")
0
? :
»Voici une opération très utile qui permet d’effectuer un « calcul » conditionnel de manière très simple : le choix conditionnel.
Contrairement aux opérations arithmétiques de base (+, -, ×, ÷), qui travaillent
toutes sur deux valeurs, le choix conditionnel travaille sur trois valeurs.
Pour cette raison, elle est représentée en JS par un opérateur un peu spécial,
? :
, constitué de deux symboles distincts,
entre lesquels va s’insérer la seconde des trois valeurs à traiter (un
peu comme le ne pas en français, qui peut se séparer en deux pour
accueillir d’autres mots : Jean ne viendra pas dîner).
Une expression qui utilise l’opérateur de choix conditionnel ? :
s’appelle une expression conditionnelle.
L’utilisation typique du choix conditionnel utilise une comparaison comme premier argument :
(comparaison) ? valeur-si-vrai : valeur-si-faux
où comparaison
est une opération de comparaison,
valeur-si-vrai
est la valeur à retourner si le résultat de
la comparaison
est true
, et
valeur-si-faux
est la valeur à retourner si le résultat de
comparaison
est false
.
Quelques exemples devraient suffire à clarifier le fonctionnement du choix
conditionnel. Pour tester ces exemples, définissez d’abord les variables
sexe
, nombre
et montant
en faisant exécuter
une et une seule expression, à votre choix, parmi chacun des trois
groupes suivants :
sexe = "F"
sexe = "M"
nombre = 0
nombre = 1
montant = 10
montant = 100
Faites maintenant exécuter les expressions conditionnelles suivantes :
(sexe == "F") ? "Madame" : "Monsieur"
"Bonjour " + ((sexe == "F") ? "Madame" : "Monsieur")
(nombre > 0) ? "Vous avez du courrier" : "Pas de courrier"
(montant < 50) ? "Pas très cher…" : "Plutôt cher !"
Les résultats obtenus varieront en fonction des valeurs des variables
sexe
, nombre
et montant
, donc en fonction
des choix que vous avez faits ci-dessus.
La valeur qui vient avant le ?
est le premier argument de
l’opérateur ? :
, celle qui vient entre le ?
et le
:
en est le deuxième argument, et celle qui vient après le
:
le troisième. Il est important de bien repérer les
sous-expressions qui correspondent à chacun des trois arguments dans un choix
conditionnel :
(sexe == "F") ? "Madame" :
"Monsieur"
(sexe == "F") ? "Madame" :
"Monsieur"
(sexe == "F") ? "Madame" : "Monsieur"
La forme générale du choix conditionnel est comme suit :
valeur-booléenne ? valeur-si-vrai : valeur-si-faux
En principe, le premier argument pourrait être une constante, true
ou
false
:
true ? 800 : 1000
800
false ? 800 : 1000
1000
Il y a cependant peu d’intérêt à écrire une expression conditionnelle si on connaît déjà la valeur du premier argument au moment de la rédiger. C’est la raison pour laquelle le premier argument est presque toujours une variable ou une comparaison faisant intervenir une variable.
Syntaxiquement, les opérations suivantes s’expriment non pas à l’aide d’un
opérateur (comme +
, -
, *
, /
ou
? :
), mais à l’aide d’une syntaxe propre aux objets, que
nous verrons plus loin. Pour le moment, il faut simplement accepter qu’elles
s’expriment avec une syntaxe particulière, qui sera démythifiée plus tard.
Opérations mathématiques
Les fonctions Math.max()
et
Math.min()
servent à trouver le maximum et le minimum de
deux valeurs numériques. Les valeurs à traiter – appelées arguments – doivent être données entre parenthèses après le nom de
l’opération, séparées l’une de l’autre par une virgule :
Math.min(15, 10)
10
Par la règle du chaînage, chacun des arguments peut être une sous-expression retournant une valeur numérique :
Math.min(3 + 2, 4)
4
Math.max(3 + 2, 4)
5
Math.max(Math.min(5, 2), 4)
4
Opérations sur les chaînes de caractères
Les opérations suivantes travaillent sur les chaînes de caractères. Elles
s’expriment en ajoutant le nom de l’opération après une expression qui
retourne une valeur caractère. Éventuellement, si l’opération nécessite d’autres
valeurs que la chaîne elle-même, celles-ci sont données en arguments entre
parenthèses après le nom de l’opération, séparées l’une de l’autre par une virgule
s’il y a plus d’une, comme pour Math.max()
et
Math.min()
.
.length
"joselito".length
8
.charAt()
"joselito".charAt(2)
"s"
Notons que les positions sont numérotées à partir de zéro (0).
.slice()
"joselito".slice(2, 5)
"sel"
Le caractère en position finale est exclu de la sous-chaîne retournée. Si le second argument est omis, tout le reste de la chaîne est retourné :
"joselito".slice(2)
"selito"
.toUpperCase()
"joselito".toUpperCase()
"JOSELITO"
Les caractères qui ne sont pas des lettres minuscules restent inchangés :
"23
décembre".toUpperCase()
"23
DÉCEMBRE"
.toLowerCase()
"JOSELITO".toLowerCase()
"joselito"
Par la règle du chaînage, ces opérations peuvent bien sûr être chaînées :
"joselito".slice(2, 5).toUpperCase()
"SEL"
Math.max("joselito".length * 2, 15)
16
Considérons une expression comme :
prix
Ce qu’on obtient comme résultat de cette expression dépend évidemment des énoncés qui ont été exécutés précédemment. Si la variable n’a jamais été définie, on obtiendra un message d’erreur, par exemple :
Uncaught ReferenceError: prix is not defined
Si, au contraire, la variable a été définie, on obtiendra comme résultat la valeur qui y est couramment stockée. Cette valeur dépend bien sûr de l’assignation qui a donné sa dernière valeur à la variable.
Pour pouvoir évaluer les expressions en tenant compte des énoncés passés, JS garde en permanence une trace de quelles variables sont définies et de la valeur de chacune. Cette trace est conservée en mémoire, par l’interprète JS, dans ce qu’on appelle l’environnement d’exécution, ou simplement l’environnement.
En première approximation, on peut considérer l’environnement comme une commode à tiroirs, dont certains portent un nom. Chaque tiroir peut contenir une (et exactement une) valeur JS, c’est-à-dire une valeur simple (numérique, caractère ou « ésotérique ») ou un pointeur à un objet :
À chaque variable correspond un tiroir de l’environnement, mais certains tiroirs ne correspondent pas à une variable définie par assignation; nous y reviendrons sous peu (nous ne les avons pas inclus dans notre exemple). Pour cette raison, les tiroirs de l’environnement s’appellent membre de l’environnement, et non « variable ». L’environnement hypothétique ci-dessus pourrait résulter, par exemple de la suite des trois assignations suivantes :
Jean = 459
Luc = "Québec"
Marie = "Montréal"
Les trois premiers membres de l’environnement dans notre exemple correspondraient
aux variables Jean
, Luc
et Marie
.
Comme pour les variables, deux membres ne peuvent pas porter le même nom et le nom d’un membre constitue en lui-même une expression JS valide, dont le résultat est la valeur contenue dans le membre. Par exemple :
Jean
459
Luc
"Québec"
Comme pour les variables, il n’y a pas de limite sur le nombre de membres qu’il peut y avoir dans l’environnement.
Quels sont donc les membres de l’environnement qui ne sont pas des variables ? Chaque type d’environnement où du JS peut s’exécuter possède des membres statutaires, c’est-à-dire des membres qui existent dans l’environnement avant même que ne s’exécute le premier énoncé d’un programme ou que l’on n’ouvre la console JS. Ces membres sont dits statutaires; ils sont dans l’environnement dès sa création, ils ne sont pas créés par un énoncé d’assignation. Les membres statutaires sont très importants, certains sont aussi utiles que les opérations de base du JS comme +, -, * et /.
Le type d’environnement qui nous intéresse, l’environnement « navigateur Web », ne fait pas exception. Avant même que ne s’exécute le premier énoncé d’une page Web ou que ne début une session à la console JS, l’environnement contient un grand nombre de membres statutaires, chacun stockant une valeur JS. Rappelons que les membres statutaires n’étaient pas montrés dans l’exemple d’environnement ci-dessus.
Un des membres statutaires de l’environnement navigateur Web est
innerWidth
. On peut donc formuler à la console JS l’énoncé suivant,
même si on n’a jamais assigné de valeur à « innerWidth
» :
innerWidth
1600
La réponse que vous obtenez pourrait être différente, puisqu’elle dépend de
réglages spécifiques dans votre navigateur. Un autre membre statutaire de
l’environnement navigateur Web est name
. Vous pouvez connaître la
valeur qu’il contient en tapant l’expression suivante dans la console JS :
name
""
La valeur contenue dans name
est donc de type caractère et il s’agit
de la chaîne vide.
Les membres statutaires ne sont pas des variables, et la plupart ne peuvent pas
être modifiés. Par exemple, closed
est dans ce cas :
closed
false
(false
est une des valeurs spéciales évoquées plus tôt). Si on essaie
de modifier la valeur de closed
:
closed = 'autruche'
"autruche"
L’assignation semble avoir réussi, mais si on redemande la valeur de
closed
:
closed
false
force est de constater que la valeur n’a pas changé.
Les navigateurs modernes comptent plus de 200 membres statutaires. C’est la raison pour laquelle nous ne les avions pas inclus dans l’exemple d’environnement donné ci-dessus.
Poursuivons notre exploration de l’environnement navigateur Web, dont un autre
membre statutaire est Math
:
Math
▸Math { … }
La puce "▸" au début de la réponse obtenue indique que la valeur de
Math
est un pointeur à un objet. Structurellement, un
objet est similaire à l’environnement, c’est-à-dire analogue à un
ensemble de « tiroirs » étiquetés, chacun contenant exactement une valeur JS. Ces
« tiroirs » s’appellent aussi « membres », comme ceux de l’environnement. Le mot qui
suit la puce indique le type de l’objet pointé. Ici, le type de l’objet
pointé est identique au nom du membre de l’environnement, mais ce n’est pas toujours
le cas.
Quelque part dans la mémoire de l’interprète JS, il y a donc un objet de type
Math
, que l’on pourrait représenter ainsi :
Notons que cet objet n’est pas dans le tiroir Math
de
l’environnement; en effet, un objet n’est pas une valeur JS, et un tiroir
ne peut contenir que une valeur JS :
Ce qui se trouve dans le tiroir Math
est un pointeur à
l’objet. Un pointeur est une « adresse » interne à l’interprète JS, que celui-ci
peut utiliser pour accéder à l’objet en mémoire. La façon de représenter la relation
entre l’environnement et l’objet pointé par Math
est celle-ci :
Nous avons inscrit "#678" à titre illustratif comme contenu du tiroir
Math
, mais en fait, JS n’affiche jamais directement la valeur interne
d’un pointeur à un objet (ce ne serait d’ailleurs d’aucune utilité); il nous montre
plutôt, comme nous avons vu, la puce "▸" suivie du type de l’objet pointé.
L’important est que, pour l’interprète JS, le contenu du tiroir permet d’accéder à
l’objet pointé.
Digression : Exploration d’un objet dans la console
Dans l’affichage que la console JS fait d’un pointeur à un objet, si on clique
sur la puce "▸" qui précède le type d’objet, l’affichage se « déplie » en un
aperçu de l’objet pointé : une liste alphabétique des noms de membres présents
dans l’objet, chacun suivi de sa valeur. Pour le membre Math
de
l’environnement, l’affichage obtenu après dépliage commence ainsi :
Parmi les membres visibles dans l’image, on remarque que certains sont
eux-mêmes précédés de la puce "▸". Les membres abs
,
acos
, acosh
, par exemple, sont dans ce cas. Ces
membres sont eux-mêmes des pointeurs à des objets (dans notre métaphore des
commodes, chacun de ces objets pointés est une commode quelque part dans la
mémoire de l’interprète JS). Ces membres peuvent aussi être « dépliés »,
récursivement, en cliquant sur la puce. Par exemple, si on « déplie »
abs
, on obtient :
Il est possible, de cette façon, d’explorer un objet pointé par un membre de
l’environnement dont on connaît le nom. Notons qu’on peut explorer
l’environnement lui-même par le truchement du membre statutaire
globalThis
, qui contient un pointeur à l’environnement lui-même !
Si vous le faites avec Firefox, notez que la plupart des membres de
globalThis
(donc, de l’environnement) sont regroupés sous
l’entrée « ▸<default properties>
» (Chrome et Edge les affichent
normalement).
Abus de langage utile et répandu
Lorsqu’on parle de l’objet pointé par un membre de l’environnement dont on
mentionne le nom, par exemple si on dit « l’objet pointé par Math
»,
il arrive souvent qu’on laisse tomber les mots « pointé par ». On dirait ainsi
« l’objet Math
». Il s’agit bien sûr d’un abus de langage, puisque le
membre Math
ne contient pas un objet, mais seulement un pointeur à un
objet.
Il est pratique de considérer l’environnement lui-même comme un objet.
L’environnement est le seul objet dont les membres peuvent être nommés directement
dans une expression JS. Les membres des autres objets ne peuvent pas être nommés
directement dans une expression JS. Ainsi, même si l’objet
Math
possède un membre PI
, si on tape ce nom à la
console, on obtient une erreur :
PI
Uncaught ReferenceError: PI
is not defined
L’opérateur « . », aussi appelé accès à un membre, vient à la rescousse et permet d’accéder indirectement au membre en question :
Math.PI
3.141592653589793
On reconnaît bien sûr la célèbre constante mathématique π.
Auto-complétion dans la console
Si vous avez copié-collé l’expression Math.PI
dans la console, nous
vous invitons à retourner dans la console et à taper vous-mêmes seulement les
trois caractères
Mat
. Vous verrez apparaître ce qu’on appelle une « fenêtre
d’auto-complétion ». L’auto-complétion est une fonctionnalité très
répandue des outils de programmation, qui suggère à l’utilisatrice différentes
façons possibles de compléter ce qu’elle est en train de taper. Dans votre cas,
les deux continuations proposées dans la fenêtre d’auto-complétion sont
Math
et MathMLElement
. Pourquoi ces deux propositions ? Parce que ce sont
les deux membres de l’environnement dont le nom commence par Mat
.
Avec la souris, ou avec les touches ↑ et ↓ suivies de Entrée, on peut choisir la continuation voulue dans la fenêtre
d’auto-complétion. On peut aussi ignorer les suggestions et simplement continuer à
taper. Pour le moment, choisissez la continuation Math
. Ce sera exactement comme si vous veniez de taper vous-même
Math
.
Appuyez maintenant sur la touche ".". Comme le "." est l’opérateur d’accès à un
membre, une nouvelle fenêtre d’auto-complétion s’ouvre, proposant comme
continuations possibles tous les membres de l’objet Math
. Vous n’avez
qu’à y piger le nom de membre voulu, par exemple PI
. L’expression
inscrite à la console devient Math.PI
, comme si vous l’aviez tapée en
entier vous-même. Vous pouvez alors faire Entrée, comme
d’habitude, pour la faire exécuter.
L’auto-complétion fonctionne non seulement avec les membres statutaires, mais également avec les variables définies par la programmeuse.
Comme il a été dit précédemment, l’opérateur « . » a une priorité plus haute que celle de n’importe quel autre opérateur. Il prend à gauche un pointeur à un objet et à droite le nom du membre à interroger. L’opération retourne le contenu du membre interrogé.
Nous verrons plus loin que l’opérateur "." peut aussi s’utiliser avec une valeur simple à gauche. C’est l’opérateur "." que l’on retrouve dans la syntaxe particulière de certaines opérations vues précédemment.
L’objet Math
Ce n’est pas sans raison que nous avons choisi Math
comme
membre statutaire à explorer. Math
est un de ces membres statutaires,
évoqués plus tôt, qui fournissent des fonctionnalités essentielles pour la
programmation en JS. En fait, Math
est statutaire non seulement dans
l’environnement navigateur Web, mais dans tous les types d’environnements
JS. C’est un membre statutaire au langage JS lui-même ou
intrinsèque au JS.
Avant de pousser plus avant notre exploration de l’objet Math
,
cependant, il nous faut introduire les objets de type function.
Certains objets sont de type function; on les appelle – de façon assez peu imaginative – « fonctions ». Métaphoriquement, ces objets possèdent, en plus d’un ensemble de tiroirs, une mécanique interne qui leur permet d’effectuer certains traitements sur des données qu’on leur fournit. C’est une généralisation du concept de fonction mathématique, comme +, -, ×, ÷, dont on peut imaginer qu’une « mécanique interne » leur permet d’effectuer un calcul sur les nombres qu’on leur fournit.
Si vous avez lu la digression ci-dessus, vous aurez vu que le membre abs
de l’objet Math
pointe à
une fonction. Il s’agit de la fonction mathématique « valeur absolue », qui retourne
la valeur positive d’un nombre.
Raccourci de langage utile et répandu
Quand une expression JS se termine par un opérateur "." suivi d’un nom de membre,
l’expression complète est souvent utilisée comme si elle était le nom du membre
désigné par l’expression. Ainsi, par exemple, on dira « (le membre)
Math.abs
» pour parler de façon concise du « membre
abs
de l’objet (pointé par) Math
».
Invocation de fonction
Faisons afficher la valeur de Math.abs
:
Math.abs
▸function
abs()
Il s’agit bien d’un pointeur à une fonction. Pour utiliser la fonction, autrement
dit pour « déclencher sa mécanique interne », il faut l’invoquer (on dit
aussi l’appeler ou l’exécuter), grâce à un type d’expression JS
que nous n’avons pas encore vu : l’invocation de fonction, qui consiste à
mettre des parenthèses ( )
après le nom de la fonction. Ce qu’il faut
écrire entre les parenthèses est dicté par le type et le nombre de valeurs sur
lesquelles la fonction opère. Dans le cas de la valeur absolue, il s’agit d’une
fonction qui s’applique à une seule valeur numérique, on utilisera donc une
invocation de la forme :
Math.abs(-876)
876
où ce qu’on met entre parenthèses pourrait être n’importe quelle sous-expression donnant une valeur numérique.
Une valeur passée à une fonction lors d’une invocation de fonction est appelée argument de la fonction. On utilise aussi les mots « paramètre » et « opérande ».
Nous avons déjà rencontré précédemment, dans un autre
contexte, deux autres fonctions de l’objet Math
: Math.min
et Math.max
qui doivent être invoquées avec deux arguments, que l’on
sépare l’un de l’autre par une virgule :
Math.min(15, 10)
10
Une autre fonction est Math.random
, qui génère un nombre
aléatoire entre 0 et 1, qui n’exige aucun argument. Il faut quand même
inscrire les parenthèses ( )
, pour indiquer que la fonction doit bel et
bien être invoquée :
Math.random()
0.8307841400124085
Comme le résultat est aléatoire, une deuxième invocation donne presque assurément un résultat différent :
Math.random()
0.920563795460914
Si on omet les parenthèses ( )
, on obtient simplement la valeur de
Math.random
, qui est bien sûr un pointeur à une fonction :
Math.random
▸function
random()
Si on essaie d’« invoquer » autre chose qu’un pointeur à une fonction, on obtient une erreur :
Math.PI(45)
Uncaught TypeError:
Math.PI is not a function
Résultat retourné par une fonction
Le résultat retourné par une fonction est toujours une valeur
JS unique. Ce peut être une valeur numérique, caractère, un pointeur à un objet ou
même une valeur ésotérique (par exemple undefined
).
Invocation de fonction comme sous-expression
Puisqu’une invocation de fonction est une expression JS, par la règle du chaînage, on peut l’intégrer comme sous-expression dans une expression plus longue. Par exemple :
Math.random() + 100
100.03573473194079
Math.min(Math.max(100, 78), Math.max(-25,
-30))
-25
Une convention répandue en orientation-objet, quand on parle d’un membre qui est
une fonction, est d’inscrire des parenthèses vides juste après son nom. On parlera
ainsi simplement de Math.abs()
, au lieu de dire au long « la fonction
Math.abs
». Notons que le fait d’utiliser les parenthèses vides
indique simplement qu’il s’agit d’une fonction et ne présume pas que la fonction
doit être invoquée sans argument – même si cela peut être le cas, comme
pour Math.random()
.
Jusqu’à maintenant, les seuls membres nommés par la programmeuse sont les variables. Nous verrons plus tard dans le cours d’autres situations où la programmeuse doit choisir un nom de membre, par exemple lorsqu’elle crée ses propres fonctions. Les mêmes règles que pour les noms de variable s’appliquent alors. Notons que certains membres statutaires ou qui ne sont pas créés par assignation peuvent porter un nom qui ne respecte pas ces règles.
Certains auteurs classent les différents membres d’un objet ou de l’environnement en deux groupes : les propriétés et les méthodes. Un membre est considéré « méthode » s’il pointe à une fonction et « propriété » dans tous les autres cas. Ce sont des appellations courantes dans la terminologie de l’orientation-objet. Cependant, en JS, la distinction est peu utile, étant donné que la valeur d’un membre peut passer d’un type à un autre par simple assignation. Une méthode peut donc devenir une propriété, et vice-versa, à la suite d’une simple assignation.
Même s’il nous arrivera régulièrement d’utiliser le mot propriété, dans le sens ci-dessus, nous préférerons habituellement le terme plus général de « membre ». Bien entendu, un membre non statutaire de l’environnement est le plus souvent appelé simplement « variable ».
Comme nous avons évoqué précédemment, l’opérateur « . » peut aussi être utilisé
avec, à gauche, n’importe quelle valeur simple (sauf null
et
undefined
). On peut imaginer que, lors de l’application de
l’opérateur « . » à une valeur simple, JS crée un objet temporaire avec
certains membres prédéfinis en fonction du type de la valeur simple. Après exécution
de l’expression, l’objet temporaire est simplement détruit, c’est-à-dire éliminé de
la mémoire de l’interprète JS.
Nous avons déjà vu précédemment certaines opérations
(.charAt()
, etc.) s’exprimant avec l’opérateur « . ». En voici deux
autres.
.toString()
Cette fonction peut être utilisée avec toute valeur JS (sauf
null
et undefined
); elle retourne une représentation
caractère de la valeur. Voici quelques exemples :
(75-100).toString()
"-25"
true.toString()
"true"
Math.toString()
"[object
Math]"
Math.abs.toString()
"function
abs() { [native code] }"
Utilisée avec une chaîne de caractères, .toString()
ne
change rien :
"abc".toString()
"abc"
Si on utilise .toString()
avec une constante numérique, il faut mettre
une espace avant le .
, car sinon ce dernier serait interprété comme
séparateur décimal et obtiendrait une erreur de syntaxe :
8 .toString()
"8"
La fonction .toString()
est remarquable parce que c’est une des rares
fonctions qui peut s’appliquer à n’importe quelle valeur JS (sauf null
et undefined
), cependant, en pratique, elle est rarement très
utile.
.toFixed()
Une fonction nettement plus utile est .toFixed()
. Appliquée
à une valeur numérique, elle l’arrondit au nombre de décimales donné en argument
(zéro si l’argument est omis), puis la transforme en chaîne de caractères :
(112*1.15).toFixed(2)
"128.80"
(1.15).toFixed(5)
"1.15000"
Math.PI.toFixed(3)
"3.142"
Math.PI.toFixed(0)
"3"
Math.PI.toFixed()
"3"