III. Expressions et opérateurs▲
Ce chapitre a pour but d'introduire les expressions et opérateurs utilisés en JavaScript. Les utilisateurs de Java, C ou C++ ne seront pas surpris par ce qui suit. Pour les autres, il faudra qu'ils prennent l'habitude de manipuler des opérateurs donnant à certaines instructions ou expressions des allures cabalistiques, mais ils se feront assez vite à ce formalisme qui ne présente, au bout du compte, aucune difficulté.
III-A. Les expressions▲
De façon générale, et quel que soit le langage utilisé, une expression est une suite de caractères pouvant être interprétée de façon à lui associer une valeur. JavaScript n'échappe pas à la règle !!!
Les expressions les plus simples sont celles ne faisant intervenir aucun opérateur. Elles ne contiennent donc qu'un littéral.
0
.
314e
+
1
//
littéral
numérique
"
Expression
"
//
littéral
chaîne
MonIdent //
Identificateur
de
variable
false
//
littéral
booléen
function
(x){
return
x+
1
}
//
littéral
fonction
{
Nom:
"
Terieur
"
,
Prenom:
"
Alex
"
}
//
littéral
objet
[
3
,
"
OK
"
,
true
,
[
null
,
12
]
,
success]
//
littéral
tableau
Ces expressions simples peuvent être combinées entre elles (ou à d'autres), pour construire des expressions plus complexes, à l'aide d'opérateurs. Certains de ces opérateurs sont communs à différents types de littéraux (bien que leur sémantique soit différente), d'autres sont spécifiques. Par exemple, l'opérateur « + » peut être utilisé pour concaténer (mettre à la suite) deux chaînes de caractères ou pour additionner deux valeurs numériques. L'opérateur « == » est un opérateur booléen dont les deux opérandes peuvent être soit numériques, soit chaînes, soit booléens. Ils peuvent même être de types différents… On verra que dans le cas d'une comparaison nombre # chaîne, par exemple, JavaScript opère au préalable une conversion.
III-B. Les opérateurs▲
Ces opérateurs disposent de deux caractéristiques syntaxicosémantique : la priorité et le sens d'associativité (gauche-droite ou droite-gauche).
En voici la liste :
Opérateur | Priorité | Sens | Types opérandes | Fonction |
. ( ) [ ] |
15 | GD | Objets / Propriétés Fonctions / Arguments Tableau / entier |
Accès à une propriété Appel de fonction Indexage de tableau |
++ -- - ~ ! typeof delete void new |
14 | DG Unaire |
Nombre Nombre Nombre Entier Booléen Indifférent Variable Indifférent Nom de constructeur |
Pré ou post incrémentation Pré ou post décrémentation Moins (Inversion) Complément à 1 binaire NON logique Rend le type de la donnée Rompt l'accès à une propriété Rend une valeur indéfinie Crée un nouvel objet |
* / % |
13 | GD | Nombres | Multiplication Division Reste modulo |
+ - |
12 | GD | Nombres | Addition Soustraction |
+ | 12 | GD | Chaînes | Concaténation |
<< >> >>> |
11 | GD | Entiers | Décalage des bits à gauche Décalage à droite (extension signée) Décalage à droite (extension à zéro) |
< <= > >= |
10 | GD | Nombres ou Chaînes | Inférieur à… Inférieur ou égal à… Supérieur à… Supérieur ou égal à… |
== != === !== |
9 | GD | Indifférent | Test d'égalité Test d'inégalité Test d'identité Test de non identité |
& | 8 | GD | Entiers | ET binaire |
^ | 7 | GD | Entiers | OU exclusif binaire |
| | 6 | GD | Entiers | OU binaire |
&& | 5 | GD | Booléens | ET logique |
|| | 4 | GD | Booléens | OU logique |
? : | 3 | DG | Booléen / Indifférent / Indifférent (ternaire) |
Opérateur conditionnel |
= | 2 | DG | Variable / Indifférent | Affectation |
*=, /=, %= +=, -= += <<=, >>=, >>>= &=, ^=, |= |
2 | DG | Variable / Nombre Variable / Nombre Variable / Chaîne Variable / Entier Variable / Entier |
Affectation avec opération |
, | 1 | GD | Indifférent | Évaluation multiple |
III-B-1. Priorité et sens d'évaluation▲
L'utilisation des opérateurs dans une expression impose, nous venons de le voir, des contraintes plus ou moins lâches sur les opérandes. Par exemple l'expression C1*C2 n'aura de sens que si C1 et C2 sont (ou peuvent se ramener) à des valeurs numériques. Par contre "C1"*"C2" n'aura pas de sens et provoquera donc une erreur, alors que "12"*"3" sera admis tout comme "12"*3 ou 12*"3". Par contre la valeur finale de l'expression, le résultat, sera d'un type bien précis. Dans le cas présent, quelle que soit l'écriture envisagée, la valeur du résultat sera le nombre 36 !!!
Ce qui vient d'être dit est valable, ainsi que nous allons le voir, pour bien d'autres opérateurs. Le seul opérateur jouant des tours inattendus est l'opérateur + dont la signification contient une ambiguïté.
"
3
"
-
2
//
soustraction
:
opérandes
ramenés
à
des
nombres
"
3
"
/
'
2
'
//
division
:
opérandes
ramenés
à
des
nombres
'
3
'
<
<
'
2
'
//
décalage
gauche
:
opérandes
ramenés
à
des
entiers
'
3
'
=
=
3
//
test
:
opérandes
ramenés
à
des
nombres
12
>
>
"
2
"
//
décalage
droite
:
opérandes
ramenés
à
des
entiers
3
%
'
2
'
//
modulo
:
opérandes
ramenés
à
des
entiers
"
3
"
+
2
//
concaténation
:
opérandes
ramenés
à
des
chaînes
3
&
'
2
'
//
ET
binaire
:
opérandes
ramenés
à
des
entiers
"
4
"
|
3
//
OU
binaire
:
opérandes
ramenés
à
des
entiers
Les caractéristiques des opérateurs (priorité ou sens d'associativité) ne sont pas une vue de l'esprit ou une convention prédéfinie qui les impose. Cela découle directement de l'analyseur du langage et en particulier, d'une part du niveau d'introduction des opérateurs dans la grammaire et, d'autre part, de la récursivité (gauche ou droite) des règles concernées. C'est dans ce sens que l'on a parlé plus haut de caractéristiques syntaxicosémantiques. Pour illustrer cela, considérons un exemple simple :
Sélectionnez
|
Dans l'arbre de dérivation ci-dessus, nous avons négligé la partie purement lexicale qui n'apporte rien à notre propos. Néanmoins, cet arbre montre bien que seul le niveau d'introduction des opérateurs dans les règles syntaxiques définit leur priorité. Plus bas est le niveau d'introduction d'un opérateur, plus il est prioritaire. Si au lieu d'introduire l'opérateur + dans Exp et * dans Term, on avait procédé à l'inverse, + serait devenu prioritaire sur *. Par ailleurs, on peut constater que les règles sont en récursivité gauche : « pour évaluer l'expression, il faut d'abord évaluer l'expression fille qui est à gauche pour laquelle il faut… ». D'où un sens d'évaluation de la gauche vers la droite ! Nous avons rajouté en grisé des parenthèses pour bien montrer l'ordre des évaluations. Mais celles-ci sont tout à fait redondantes et la valeur de cette expression est bien 24.
III-B-2. Les opérateurs arithmétiques▲
Nous ne nous étendrons pas ici sur les opérateurs arithmétiques habituels, + (addition), * (multiplication), / (division), - binaire (soustraction) ou - unaire (inversion). Nous préciserons toutefois que le % (modulo) ne se contente pas d'opérer sur des entiers, mais permet d'obtenir des restes de divisions rationnelles.
Par exemple,
5
.
6
%
3
.
21
=
2
.
3899999999999997
.
Nous nous arrêterons, par contre, sur les opérateurs d'incrémentation (+1) ou de décrémentation (-1). Ces opérateurs, selon qu'ils sont placés avant ou après la variable concernée opèrent l'opération soit a priori, soit a posteriori. Par exemple l'instruction j = i++; est équivalente à j = i; i = i+1;. Si l'on avait voulu affecter à j la valeur de i+1, il aurait fallu écrire j = ++i; ce qui est équivalent à i = i+1; j = i;. Ce que l'on vient de dire s'applique de la même façon à l'opérateur --.
À noter que si l'utilisation de tels opérateurs intervient dans une chaîne de caractères, vous pouvez rencontrer un problème…
Ce problème est dû à la confusion qui existe hélas, dans JavaScript, entre le + de concaténation et les opérateurs arithmétiques comportant le signe +.
Pour en revenir aux priorités des opérateurs : après avoir exécuté les instructions les instructions i=3; j=7; l'exécution de i=i+++j va affecter à i la valeur 10 tandis que j conserve la valeur 7. En effet, ++ étant prioritaire sur +, l'évaluation va s'opérer selon i=(i++)+j et non i=i+(++j). Donc i va bien prendre la valeur 10 et la postincrémentation de i est perdue !!!!! Cette opération se réalise en fait selon le mode suivant : R=i; i=i+1; i=R+j où R est un registre de travail. Dans le second cas qui aurait pu avantageusement s'écrire i+=++j, les valeurs finales auraient été i : 11 et j : 8.
III-B-3. Les opérateurs d'égalité et d'identité▲
L'opérateur d'égalité (==) renvoie une valeur booléenne. Le test s'opère différemment selon que les opérandes sont de type primitif ou de type composé. Pour les types primitifs le test s'opère par valeur, c'est-à-dire que le résultat du test sera true si et seulement si les arguments sont identiques (nombres ou booléens de même valeur, chaînes comportant une suite identique de caractères)ou peuvent l'être par conversion de chaînes ou de booléens vers des nombres. Dans le cas contraire, le résultat vaudra false. Pour les types composés (tableaux, objets, fonctions), le test s'effectue par référence, c'est-à-dire que le résultat sera true si les deux arguments font référence aux mêmes objets.
Il faut noter en outre les égalités suivantes :
- si les deux opérandes ont pour valeur null ou sont indéfinis, ils sont égaux ; (1)
- si l'un des opérandes a pour valeur null et l'autre est indéfini, ils sont égaux. (2)
Enfin, dans le cas où les arguments sont de types différents, les règles suivantes doivent être appliquées (reprenant en cela ce que nous avons vu précédemmentDes-booléens-qui-sortent-de-l'ordinaire…) :
- si un opérande est une chaîne et l'autre un nombre, reconsidérer le test après avoir converti (si cela est possible) la chaîne en nombre ; (3)
- si l'un des opérandes est booléen, reconsidérer le test après avoir converti respectivement true en 1 et false en 0. (4)
L'opérateur d'identité (===) a un comportement quelque peu différent selon qu'il porte sur des objets de type primitif ou des objets de type composé.
Les objets de type composé : l'opérateur d'identité se comporte exactement comme l'opérateur d'égalité ;
Les objets de type primitif : l'opérateur d'identité se comporte exactement comme l'opérateur d'égalité, mais il n'opère aucune conversion !!!
Ainsi, tous les exemples du paragraphe précédent retourneront « false » à un test d'identité. De même « null » ne sera plus assimilé à l'état indéfini.
En définitive, la relation d'identité sera satisfaite par ses opérandes si et seulement si ceux-ci sont de même type et ont même valeur.
À la limite entre les types primitifs et composés, voyons comment se comportent ces opérateurs à l'aide de trois exemples où seule l'initialisation de deux variables, s1 et s2 diffère de l'un à l'autre. La suite, identique pour les trois, teste l'égalité et l'identité de ces deux variables…
Sélectionnez
|
Sélectionnez
|
Alert(out) |
Sélectionnez
|
Alert(out) | |
Sélectionnez
|
Alert(out) |
Le premier exemple montre le comportement des opérateurs d'égalité et d'identité sur deux chaînes, le second, sur une chaîne et un objet chaîne, le troisième sur deux objets chaînes (nous reviendrons plus loin sur la distinction chaîne # objet chaîne).
III-B-4. Les opérateurs de comparaison▲
Nous ne nous étendrons pas sur les opérateurs de comparaison dans le cas où les opérandes sont numériques. Chacun sait qu'ils vont être utilisés dans les expressions booléennes en général (comme les précédents) et en particulier dans les instructions if ou while, for ou do que nous verrons ensuite. Précisons néanmoins qu'ils n'admettent pour opérandes que des nombres ou des chaînes de caractères (et éventuellement, mais l'intérêt est médiocre, des booléens). Dans le cas d'opérandes de type différents, il y a tentative de conversion vers un nombre. Si la conversion est possible et la comparaison par voie de conséquence, le test est évalué, sinon l'évaluation est false quel que soit l'opérateur.
Évaluer les expressions… | Résultat |
Sélectionnez
|
|
Sélectionnez
|
|
Sélectionnez
|
|
Sélectionnez
|
Nous avons précédemment étudié le comportement des opérateurs d'égalité et d'identité lorsque les opérandes sont des chaînes. Les opérateurs de comparaison sont eux aussi utilisés pour les chaînes de caractères. Dans ce cas, la comparaison s'opère suivant l'ordre lexicographique. Par exemple, "Pascal" < "Perl" est évalué à true. Lorsque les deux chaînes comparées ont une partie commune en tête, c'est la longueur des chaînes qui sert pour l'évaluation. Par exemple, "Java" >= "JavaScript" est évalué à false. Un autre opérateur reçoit pour opérandes des chaînes de caractères : +, opérateur de concaténation. Cet opérateur a pour effet de construire une chaîne en réunissant les chaînes opérandes. Par exemple : "JavaScript, "+'c\'est '+"chouette" a pour valeur "JavaScript, c'est chouette".
Il est important de noter qu'en cas d'ambiguïté, priorité est donnée aux opérateurs de chaîne par rapport aux opérateurs de nombre. Ainsi, "12"+7 prend pour valeur, non pas 19, mais "127" ! Dans le cas on l'on veut opérer un calcul de ce type, il faudra auparavant forcer la conversion de la chaîne en nombre. Ainsi, si la variable Str contient la chaîne "12", le calcul arithmétique précédent devra s'écrire Str * 1 + 7. La multiplication force l'évaluation à convertir Str en un nombre avant de l'additionner à 7. Le résultat est alors celui attendu : 19.
Inversement, les opérateurs de comparaison privilégient la conversion vers les nombres. Ainsi "12" > 7 sera bien évalué par true, preuve qu'il y a bien eu conversion de "12" vers 12, car la comparaison lexicographique aurait donné false.
Voyons à présent si vous avez bien assimilé ce que l'on a dit depuis le début de ce chapitre… Pouvez-vous donner la valeur de 4+2+"trouille" ?
Bien ! Et maintenant, vous n'aurez donc plus aucune difficulté pour évaluer l'expression "4"+5+2 > 58 ?!…
III-B-5. Les opérateurs logiques▲
Les opérateurs logiques sont utilisés dans des expressions booléennes complexes mettant en jeu plusieurs variables. Pour ceux qui connaissent Pascal, ce langage comporte les d'opérateurs AND, OR, NOT qui réclament l'évaluation complète de l'expression dont ils font partie. Certaines versions (ou options de compilation) autorisent la génération d'un code optimisé qui retourne une évaluation de l'expression dès qu'elle est possible sans que tous les termes ou facteurs de ladite expression aient forcément été évalués. Les opérateurs logiques de JavaScript sont optimisés.
- L'opérateur ET (&&), est-il besoin de le rappeler, retourne la valeur true si et seulement si ses deux opérandes ont eux-mêmes pour valeur true ? Il convient toutefois d'insister sur l'aspect optimisation. En effet, dans le cas de l'expression 3>4 && "4"+5+2 > 58, l'opérateur && étant gauche-droite, l'évaluation va tout d'abord s'opérer sur 3>4. Ce facteur ayant pour valeur false, point n'est besoin d'évaluer le second opérande puisque d'ores et déjà, on sait que la valeur de l'expression sera false. Si, par contre, le premier facteur avait été évalué à true, l'évaluation se serait poursuivie sur le deuxième opérande.
Certains programmeurs affectionnent particulièrement ce type de fonctionnement pour faire des effets de style. Par exemple, au lieu d'écrire if(val1==val2) alert('OK'), ils préfèrent var Bool=(val1==val2) && alert('OK'). Ce faisant, si val1 n'est pas égal à val2, Bool prendra la valeur false sans que alert('OK') n'ait été évalué et donc exécuté. Si par contre val1 est bien égal à val2, le deuxième facteur sera évalué et donnera donc lieu à l'apparition de la fenêtre d'alerte. Ces deux écritures sont donc équivalentes. Mais, outre le fait que l'intérêt est difficile à saisir (!!!), cette façon de faire est totalement déconseillée. En effet, si le deuxième facteur n'est pas évalué, cela pourra provoquer une erreur de programmation si l'on n'y prend garde. De façon générale, prenez l'habitude de ne pas utiliser dans une expression booléenne des expressions à effet de bord (appel de fonction, incrémentation, décrémentation…) au-delà du premier opérande.
- L'opérateur OU ( || ) qui ne renvoie une valeur false que si ses arguments ont tous deux pour valeur false fonctionne de la même façon que l'opérateur précédent. Si l'évaluation du premier terme se révèle être true, l'expression aura pour valeur true sans avoir à évaluer la suite. Si par contre, le premier terme a la valeur false, le second sera évalué.
- L'opérateur NON ( ! ). Rien de particulier à dire de cet opérateur unaire, si ce n'est qu'il délivre une valeur de vérité inverse de celle de son opérande.
III-B-6. Les opérateurs binaires▲
Nous avons montré plus haut quelques expressions utilisant des opérateurs binaires. Ils nécessitent des opérandes numériques (ou ayant subi une conversion adéquate) et interviennent directement sur la configuration binaire du codage en complément à 2 sur 32 bits de ceux-ci. Pour ceux qui ne comprennent rien à ce charabia, ce serait trop long et mal venu ici de l'expliquer. Ils pourront si cela les intrigue consulter mon cours à ce sujet.
Ces opérateurs interviennent dans des utilisations de bas niveau sur des représentations binaires. Cela autorise des réalisations spectaculaires d'efficacité comme l'algorithme de Transformée Rapide de Fourrier (butterfly). Mais pour ceux qui ne se sentent pas concernés par ce genre de subtilité, ils peuvent sauter ce paragraphe, il ne leur en sera pas tenu rigueur…
- L'opérateur binaire ET (&) est surtout utilisé pour mettre en place des . Un masque est un nombre binaire comportant des 1 aux emplacements où on veut récupérer l'information d'autres nombres. Par exemple, supposons que l'on code sur 32 bits des informations individuelles : Jour de naissance (5 bits - [0,31]-), Mois (4 bits -[0,15]-), Année (7 bits -[0,127]-), Poids (7 bits -[0,127]-), Taille en cm (8 bits -[0,255]-). On suppose que le bogue de l'an 2000 est passé, et qu'il n'y a pas de sumotori parmi ces personnes. Pour le reste, les contraintes sont supportables… ;-)
Supposons à présent que pour l'ensemble de ces individus on veuille faire une étude statistique sur le poids. Pour chaque personne nous allons donc devoir récupérer les sept bits utilisés pour coder cette caractéristique. Pour cela, nous allons utiliser le masque suivant :
Pour chaque bit autre que les bits de poids, le résultat sera 0, puisque 0 (du masque) & X a pour valeur 0 quel que soit X. Pour le champ Poids, pour un bit de donnée à 1, le résultat sera 1 (puisque 1 & 1 = 1) et pour un bit de donnée à 0, le résultat sera 0 (puisque 0 & 1 = 0). Ainsi on récupère pour résultat les seuls bits du champ Poids. Il ne restera alors plus qu'à opérer un décalage à droite de 8 bits (ce que nous allons voir) pour obtenir la valeur effective.
- L'opérateur binaire OU ( | ), pour reprendre l'exemple ci-dessus, va nous permettre d'initialiser des champs. Supposons que le codage des caractéristiques de chaque individu soit initialisé à 0 et que nous ayons déjà chargé, dans la variable concernée, la taille de l'individu (178 cm). La variable a donc l'allure suivante :
Affectons par exemple à cet individu I la valeur de son poids : 72 kg. Un mot de 32 bits va donc être initialisé à la valeur décimale 72, soit en binaire :
On procède ensuite à un décalage à gauche de 8 bits (place occupée par le champ « Taille »), pour obtenir :
Il ne reste plus, ensuite, qu'à opérer un OU entre cette valeur et la variable contenant déjà le champ « Taille ». Chacun des bits du résultat prendra pour valeur 1 chaque fois que le bit correspondant de la variable I ou de la variable Poids (ou des deux, situation qui ne se présente pas dans notre exemple) aura pour valeur 1 et 0 sinon. Le résultat final est donc :
- L'opérateur binaire OUX (^) délivre en résultat la valeur 1 chaque fois que l'un ou l'autre (mais pas les deux) des bits correspondants des opérandes est à 1. On peut donner une application de cet opérateur dans la recherche du nombre minimum d'arêtes à suivre pour relier deux sommets d'un hypercube (certains reconnaîtront ici le calcul de la distance de Hamming). Soit donc deux points A et B dans un espace [0,1]3.
Le point A est codé 101 et le point B est codé 110. En effectuant un OU exclusif entre ces coordonnées, on obtient : Sélectionnez
Il ne reste plus qu'à compter le nombre de bits à 1 du résultat pour déterminer le nombre d'arêtes qui doivent être traversées pour relier les deux points. Cela peut se faire avec le petit script suivant : Sélectionnez
|
- L'opérateur binaire NON (~) est un opérateur unaire se plaçant avant son opérande. Il a pour fonction d'inverser l'ensemble des bits de l'opérande. Autrement dit, il délivre son complément à 1.
- L'opérateur binaire de décalage à gauche (<<) comporte deux opérandes : à gauche, le nombre à traiter et à droite le nombre de bits de décalage. Ce dernier doit être une valeur comprise entre 0 et 31. Si d'aventure il est plus grand, c'est la valeur modulo 32 qui sera prise en compte. La fonction de cet opérateur est de décaler vers la gauche l'ensemble des bits du premier opérande d'autant de places que le second l'indique en remplissant à droite par des 0 et en provoquant la perte des bits poids forts. Le fait de décaler d'un bit à gauche provoque une multiplication du nombre par 2. Le fait de le décaler de n bits provoque donc une multiplication par 2n.
- L'opérateur binaire de décalage à droite (>>) signé a les mêmes caractéristiques que le précédent quant à ses opérandes. Sa fonction consiste à décaler vers la droite l'ensemble des bits du premier opérande d'autant de places que le second l'indique. Selon que le bit poids fort de la valeur d'origine du premier opérande était à 1 ou à 0, le remplissage à gauche se fait par des bits à 1, respectivement, à 0. Les bits poids faibles sont perdus.
- L'opérateur binaire de décalage à droite (>>>) non signé a les mêmes caractéristiques que les précédents quant à ses opérandes. Sa fonction est identique à celle de l'opérateur de décalage à droite signé hormis le fait que le remplissage des bits poids forts s'opère systématiquement par des 0.
Dans les exercices qui suivent, essayez d'évaluer vous-même les expressions proposées avant de regarder le résultat (n'hésitez pas à vous référer au tableauLes-Opérateurs du début, en particulier pour la priorité des opérateurs).
III-B-7. Les opérateurs d'affectation▲
On distingue deux types d'opérateurs d'affectation : l'opérateur d'affectation simple et ceux d'affectation avec calcul. Dans les deux cas, le premier opérande doit être une variable.
- Pour ce qui concerne l'affectation simple, le deuxième opérande est indifférent (variable ou littéral de type quelconque). Comme nous l'avons vu dans le chapitre précédent, le type de l'argument affecté détermine le type de l'argument récepteur. Nous pouvons constater dans le tableauLes-Opérateurs récapitulatif que cet opérateur est droite-gauche. Il est essentiel d'insister sur le fait que l'affectation est donc effectuée via un opérateur. Cela va avoir des conséquences dans son utilisation puisqu'une affectation pourra donc être considérée comme une expression. Ainsi, nous allons pouvoir ainsi procéder à des affectations multiples.
Par exemple, l'expression a=b=c=d=3. Celle-ci va être analysée (en faisant apparaître le parenthésage : a=(b=(c=(d=3))). La première expression évaluée est d=3 qui non seulement a pour fonction d'affecter la valeur 3 à d, mais aussi de retourner la valeur 3 elle-même. Ainsi l'évaluation se poursuit sur c=3, etc. À l'issue de l'évaluation, les quatre variables a, b, c, et d auront ainsi été affectées à 3. Autre possibilité dérivée de ce qui vient d'être dit : (a=b)>3 constitue une expression booléenne tout à fait correcte qui à la fois affecte la valeur de b à a et vérifie si cette valeur est supérieure à 3.
- Les opérateurs d'affectation avec calcul réclament pour le deuxième opérande un type précis dépendant de l'opérateur concerné comme précisé dans le tableauLes-Opérateurs récapitulatif. Ces opérateurs comportent deux caractères, le premier précisant l'opération le second étant le signe d'affectation. La fonction de ces opérateurs est d'effectuer l'opération précisée sur le premier et le second opérande, puis d'affecter le résultat au premier opérande. On a donc les équivalences suivantes :
Opérateur | Exemple | Signification | Résultat |
---|---|---|---|
+= (Num) += (Chaîne) -= *= /= %= &= | = ^= <<= >>= >>>= |
a=12; a+=3 a="12"; a+="3" a=12; a-=3 a=12; a*=3 a=12; a/=3 a=13; a%=3 a=12; a&=3 a=12; a |=3 a=14; a ^=3 a=12; a<<3 a=-12; a>>=2 a=-12; a>>>=2 |
a=a+3 a=a+"3" a=a-3 a=a*3 a=a/3 a=a%3 a=a&3 a=a|3 a=a^3 a=a<<3 a=a>>2 a=a>>>2 |
a=15 a=123 a=9 a=36 a=4 a=1 a=0 a=15 a=13 a=48 a=-3 a=1073741821 |
III-B-8. Opérateurs divers▲
Nous allons voir ici les derniers opérateurs (mis à part ceux dédiés aux tableaux et aux objets) que propose JavaScript.
- Un opérateur dont vous apprendrez à apprécier la grande utilité est l'opérateur conditionnel. Celui-ci est un opérateur comportant trois opérandes (on dit qu'il est ternaire) et peut être utilisé en de multiples circonstances, chose que ne permet pas l'instruction if/else avec laquelle on pourrait faire le rapprochement.
Sa syntaxe est la suivante : <expression booléenne> ? <expression1> : <expression2>.
Son fonctionnement : • tout d'abord, l'expression booléenne (premier opérande) est évaluée.
• si cette évaluation est true, l'expression résultat prend pour valeur l'évaluation de l'expression1
(2e opérande)
• sinon, l'expression prend pour valeur l'évaluation de l'expression2 (3e opérande)
Avec cet opérateur, on peut, par exemple, construire une chaîne de caractères en choisissant des portions, prévoir dans la construction même de pages web plusieurs options, affecter différemment une variable selon sa valeur précédente ou autre, construire un lien vers une autre page s'adaptant à des informations recueillies, bref, donner une flexibilité très grande au travers d'une écriture particulièrement concise.
EssaiLe choix de page de cet essai est réalisé par :
b=prompt('Donnez une valeur…');(b<=10) ? window.open('Inferieur.html') : window.open('Superieur.html')
- L'opérateur ", " est particulier… En fait, sa principale utilisation apparaît dans les boucles bornées (for) que nous aborderons plus loin. Disons simplement que grâce à lui et une telle boucle peut porter sur plusieurs variables qui évoluerons simultanément à chaque pas de la boucle.
Les opérateurs suivants n'ont pas le graphisme du type de ceux que l'on a vu jusqu'à présent. Ce sont en fait des mots réservés du langage, c'est-à-dire des suites de caractères alphabétiques qui ne peuvent être choisis comme identificateurs de variables.
- L'opérateur typeof est un opérateur unaire placé avant son opérande. La valeur retournée est une chaîne de caractères indiquant le type de l'opérande. Cette évaluation peut donc délivrer : « number », « string », « boolean », « object », « array », « function », « null » ou « undefined ».
- L'opérateur de création d'objets, new reçoit en opérande un constructeur d'objets et délivre une instance de ce type d'objet. Nous avons déjà vu des utilisations de cet opérateur au chapitreLes-Objets précédent, aussi, nous ne nous attarderons pas sur celui-ci.
- L'opérateur delete permet de supprimer une propriété d'un objet (ou un élément de tableau) passée en argument depuis la version 1.2 de JavaScript. Il faut insister sur le fait que le delete de JavaScript n'a rien à voir avec celui de C ! Nous avons déjà précisé que la récupération d'espace mémoire en JavaScript était un processus automatique. Ici, nous supprimons seulement une propriété. Il faut néanmoins indiquer que dans une page web, tout est propriété d'un objet window. Donc un objet défini par le créateur d'une page web constitue une propriété de l'objet window et peut donc à ce titre être supprimé… sauf s'il a été créé en utilisant var auquel cas la suppression n'aura pas lieu. Par contre, l'objet window lui-même ne pourra jamais être supprimé… et cela vaut mieux ;-)
- L'opérateur void comporte un argument indifférent (variable, expression, littéral…). Il renvoie systématiquement la valeur undefined. Nous avons vu la différence subtile qu'il y avait entre le littéral null et la valeur undefined et nous avons précisé que undefined ne pouvait pas être employé en tant que littéral. L'utilité essentielle de l'opérateur void est de pallier ce défaut. Appliquons cela à un petit exemple.
Soit le programme :
Indiv=
new
Object
( );
Indiv.
naiss=
new
Date
(92
,
8
,
27
);
var
Indiv.
copie=
Indiv.
naiss;
Mois=
Indiv.
naiss.
getMonth
();
alert
('
naiss
=
'
+
Mois);
delete
Indiv.
naiss;
(Indiv.
naiss !
=
void
0
) ?
alert
('
naiss2
=
'
+
Indiv.
naiss.
getMonth
()) :
alert
("
Indiv.naiss
est
indefini
"
);
Mois=
Indiv.
copie.
getMonth
();
alert
('
Indiv.copie
=
'
+
Mois);
Ce petit exemple a plusieurs utilités : il illustre ce qui a été dit au chapitre 2 sur les objets et ce qui vient de l'être au sujet de l'opérateur delete. Celui-ci a bien supprimé la propriété naiss de l'objet Indiv, c'est-à-dire l'accès vers l'objet Indiv.naiss. Mais cet objet n'a lui-même pas été supprimé, car un autre accès, copie pointait vers lui. L'accès à l'objet Indiv.naiss n'existant plus, le test utilisant l'opérateur void nous le confirme et c'est bien alert("indefini") qui est exécuté.