Copyright © 2017-2022 Yves MARCOUX; dernière modification de cette page : 2022-01-04.

SCI6373 Programmation documentaire

Introduction aux expressions JavaScript

Index de ce texte

Yves MARCOUX - EBSI - Université de Montréal


Table des matières

Introduction

Mode de lecture recommandé, console JavaScript

Énoncés JavaScript, interaction avec la console

Le JavaScript et ses environnements

Les scripts ou programmes JavaScript

Valeurs JavaScript, valeurs simples

Constantes

Opérations simples sur valeurs simples

Variables

Règles sur les noms de variables

Utilisations types des variables

Chaînage d’expressions

Parenthésage

Priorité des opérateurs

Sous-expressions et LHS

Autres opérations

Opérations unaires

Comparaisons, valeurs booléennes

Le choix conditionnel « ? : »

Opérations à syntaxe particulière

Environnement, membres

Membres statutaires

Objets

L’opérateur « accès à un membre » ou « . »

Fonctions

Noms de membre

Propriétés et méthodes

Autres utilisations de l’opérateur « . »


Introduction

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.

Mode de lecture recommandé, console JavaScript

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 :

  1. Faire Outils → Développement web → Console web (ou Ctrl-Maj-K). Ceci ouvre la fenêtre des outils de développement Web à l’onglet Console.
  2. Cliquez sur les dans le bandeau de tête de la fenêtre qui vient de s’ouvrir, puis sélectionnez la disposition désirée. Nous recommandons l’option Ancrer à droite.

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.

Énoncés JavaScript, interaction avec la console

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.

Le JavaScript et ses environnements

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.

Les scripts ou programmes JavaScript

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&nbsp;!</title>
    </head>
    <body>
        <h1>Dites-moi vite bonjour&nbsp;!</h1>
        <form action="javascript:traiterFormulaire();">
            <p>SVP, entrez votre nom&nbsp;:
                <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 + "&nbsp;! 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.


Valeurs JavaScript, valeurs simples

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 :

  1. une valeur numérique,
  2. une chaîne de caractères (ou valeur caractère),
  3. un pointeur (ou une référence) à un objet.

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.


Constantes

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.


Opérations simples sur valeurs simples

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"

""+""
""

'' + ''
""


Variables

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

Règles sur les noms de variables

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 interdit
leç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

Utilisations types des variables

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éassignation
43    ← nouvelle valeur

y = y + 1    ← auto-réassignation
44    ← 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.


Chaînage d’expressions

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.

Parenthésage

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.

Priorité des opérateurs

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 :

  1. Les opérateurs de plus haute priorité sont exécutés avant ceux de plus basse priorité.
  2. En l’absence de parenthèses, les opérateurs d’égale priorité sont exécutés de gauche à droite.

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

  1. Comme en arithmétique élémentaire, les 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é.
  2. L’opérateur d’assignation "=" a la plus basse priorité de tous les opérateurs courants.
  3. L’opérateur "." (accès à un membre), que nous verrons sous peu, a la plus haute priorité de tous les opérateurs courants.

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.

Sous-expressions et LHS

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.


Autres opérations

Nous allons maintenant étendre un peu notre répertoire d’opérations JS. Plusieurs autres opérations s’ajouteront aussi en classe.

Opérations unaires

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

Comparaisons, valeurs booléennes

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

Le choix conditionnel « ? : »

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

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 :

Groupe 1
sexe = "F"
sexe = "M"
Groupe 2
nombre = 0
nombre = 1
Groupe 3
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 :

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.

Opérations à syntaxe particulière

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
Retourne la longueur de la chaîne, c’est-à-dire le nombre de caractères qu’elle contient :

"joselito".length
8

.charAt()
Extrait un caractère à une position spécifique dans la chaîne; la position (numérique) est donnée en argument :

"joselito".charAt(2)
"s"

Notons que les positions sont numérotées à partir de zéro (0).

.slice()
Extrait une sous-chaîne située entre deux positions spécifiques données en arguments :

"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()
Transforme en majuscules les lettres minuscules présentes dans la chaîne; elle n’a besoin d’aucun argument (mais il faut quand même inscrire les parenthèses) :

"joselito".toUpperCase()
"JOSELITO"

Les caractères qui ne sont pas des lettres minuscules restent inchangés :

"23 décembre".toUpperCase()
"23 DÉCEMBRE"

.toLowerCase()
Transforme en minuscules les lettres majuscules présentes dans la chaîne :

"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


Environnement, membres

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 :

termino1.png termino2.png termino3.png termino3a.png

À 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.

Membres statutaires

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.


Objets

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 :

termino22.png

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 :

termino5.png

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 :

termino23.png

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 :

termino20.png

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 :

termino24.png

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).

L’opérateur « accès à un membre » ou « . »

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.

Fonctions

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().

Noms de membre

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.

Propriétés et méthodes

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 ».


Autres utilisations de l’opérateur « . »

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"