Ce chapitre à 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'il 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é.
1
- 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.
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.
2
- Les Opérateurs
Ces opérateurs disposent de deux caractéristiques
syntaxico-sémantique : la priorité
et le sens d'associativité (gauche-droite
ou droite-gauche).
En voici la liste :
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
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'autre opérateurs. Le seul opérateur
jouant des tours inattendus est l'opérateur + dont la signification
contient une ambiguïté.
Exercices :
Cliquez
pour afficher la valeur...
"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 syntaxico-sémantiques.
Pour illustrer cela, considérons un exemple simple :
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.
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 reste 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 à
priori, soit à 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 --.
A noter que si l'utilisation de tels opérateurs
intervient dans une chaîne de caractère, 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 10et 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.
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, il 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édemment)
:
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)
On a vu précédemment que toute chaîne
avait pour valeur logique true. En conséquence,
on serait en droit de penser que l'expression booléenne "X"==true
a toujours pour valeur true, quelle que soit
la chaîne X
Essayons donc d'évaluer "1" == true
. Tout paraît normal...
Essayons "0"==true...
. Tiens ! La supposition précédente s'avère fausse
!!! Mais cela est bien cohérent avec les règles énoncées
ci-dessus : par la règle (4) true interprété
comme la valeur 1 vérifie donc bien
l'égalité avec la chaîne "1"convertie
elle-même en 1 par la règle (3)
(mais pas la chaîne "0") !!
Dans ces conditions, essayons "0"==false...
. Correct ! false et "0"
ramenés par la règle (4) [resp. (3)] à la valeur 0,
on obtient bien pour valeur true.
Finalement, pouvez vous répondre
à la question du début : quelle est la valeur de l'expression
booléenne "X"==true si la
chaîne X est quelconque différente
de "1"? Réfléchissez
un peu avant de regarder la réponse.
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.
A la limite entre les types primitifs et composés,
voyons comment se comportent ces opérateurs à l'aide de 3 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...
var s1 = "";
var s2 = "Bonjour"; s1 += s2;
Out
= 's1 = ' + s1+'\ns2 = ' + s2;
if (s1==s2) Out += '\nEgalite : OK';
else Out += '\nEgalite : NON OK';
if (s1===s2) Out += '\nIdentite : OK';
else out += '\nIdentite : NON OK';
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)
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.
Quelques
Exercices :
Évaluer
les expressions...
Résultat
true >= "0"
12 < "Infinity"
"13,6" <= 17
Infinity >= "n'importe
quoi"
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é 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égie
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 ?!...
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 il 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.
ATTENTION
: 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 à effets 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.
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
intriguent 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, par exemple, 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 masques. 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 bug 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 7 bits utilisés pour coder cette caractéristique. Pour cela,
nous allons utiliser le masque suivant :
( I )
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 champs 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 :
( I )
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 :
( Poids )
On procède ensuite à un décalage
à gauche de 8 bits (place occupée par le champ "Taille"),
pour obtenir :
( Poids )
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 :
( I )
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îtrons
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 :
Res = 101 ^110(011).
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:
var S=0; //Initialisation compteur
while (Resl>0) { // Tant qu'il reste 1 bit à 1..
S+=(Res & 1); // Ajout de la valeur du bit
Res>>>=1; // Décalage à droite
}
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 les 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, essayer d'évaluer vous-même
les expressions proposées avant de regarder le résultat (n'hésitez
pas à vous référer au tableau du début,
en particulier pour la priorité des opérateurs).
Quelques
Exercices :
Évaluer
les expressions...
Résultat
12-4%3!="1"+(0xD^014)
0?3:null?'6':"1"?100:true?x:12
-2+3^6>>1
~-~3&-~4<<2
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 tableau 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. A l'issue de l'évaluation, les quatre variables a, b, c, et d
auront ainsi été affectée à 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 tableau 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
:
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 une opérateur comportant 3 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
(2ème opérande)
sinon, l'expression prend pour valeur l'évaluation de l'expression2 (3ème opérande)
Avec cet opérateur, on peut, par exemple,
construire une chaîne de caractère en choisissant des portions,
prévoir dans la construction même de pages web plusieurs alternatives,
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.
Essai.... Le 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 boucle
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 mot 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'objet, new reçoit
en opérande un constructeur d'objet
et délivre une instance de ce type d'objet. Nous avons déjà
vu des utilisations de cet opérateur au chapitre
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éralnull
et la valeurundefined 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 :
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é.