Mis à part lorsqu'elles contiennent des opérateurs
induisant des effets de bord (en particulier, les opérateurs d'affectation
et d'incrémentation), les expressions qui ont été présentées
au précédent chapitre se contentent de produire une valeur mais
n'ont aucun rôle actif dans l'exécution d'un programme. L'exécution
proprement dites est réalisée grâce au répertoire
d'instructions dont dispose le langage. L'objet de ce nouveau chapitre est d'introduire
les diverses instructions utilisables sous JavaScript. Mais avant tout, il convient
de préciser que JavaScript dispose aussi de deux types d'instructions
:
-
les instructions simples qui se résument à
des instructions atomiques comme, par exemple, les instructions-expression
(s+=12; ou index--;
ou encore Res=(index > 3) ? "OK" :'KO';)...
de même que les appels de fonctions (prompt('Voulez-vous
un cafe ?'); )
- les instructions composées qui constituent donc un bloc composé
de plusieurs instructions et bordé par deux accolades {...}.
1
- Les tests
|
Les instructions de test disponibles en JavaScript sont
celles que l'on connaît pour beaucoup d'autres langages. Il s'agit de
l'instruction if et de l'instruction if...else.
La syntaxe de l'instruction if est la suivante :
if (<expression
booléenne>) <instruction>
Son fonctionnement est le même que pour les autres
langages : si le résultat de l'évaluation de l'expression est
true ou peut être converti vers true,
alors l'instruction est exécutée ; si le résultat de
l'évaluation de l'expression est false
ou peut être converti vers false, alors
l'instruction n'est pas exécutée. Il convient de noter dans
la syntaxe, l'obligation d'encadrer l'expression booléenne entre deux
parenthèses. Par ailleurs, il est bien évident que l'instruction
conditionnelle peut être simple ou composée.
La seconde forme de l'instruction est donc le
if...else dont la syntaxe est la suivante :
if
(<expression booléenne>)
<instruction 1> ;
else <instruction
2>
Son exécution, s'il est besoin de le préciser,
est le suivant : si le résultat de l'évaluation de l'expression
est true ou peut être converti en true,
alors l'instruction 1 est exécutée ; si le résultat
de l'évaluation de l'expression est false
ou peut être converti vers false, alors
c'est l'instruction 2 qui 'est exécutée. Les remarques
concernant l'instruction if s'appliquent à
l'instruction if...else. De plus, on remarquera
dans la syntaxe le point virgule précédant else.
Cela ne sera pas sans surprendre ceux qui connaissent le langage Pascal où
justement ce caractère placé à cet endroit était
totalement en défaut par rapport à la syntaxe.
|
|
Pour être précis, ce caractère ";" n'est absolument
nécessaire que dans le cas d'une écriture linéaire d'une
telle instruction. En effet, en JavaScript, le retour
à la ligne vaut le ";" (sauf quand l'instruction n'est
pas syntaxiquement finie). Ainsi, une écriture du style :
if
(<expression booléenne>)
<instruction 1>
else
<instruction 2>
|
est tout à fait correcte et admise par la syntaxe. Le retour à
la ligne après l'expression booléenne appelle une suite constituée
par l'instruction 1. Par contre, après celle-ci, l'instruction
if
est syntaxiquement achevée et donc, le retour à la ligne vaut
le ";" nécessaire à cet endroit. Conséquence
de ce qui vient d'être dit : même si le else
est, comme ici, suivi d'un retour à la ligne, l'instruction placée
à la ligne suivante fera partie intégrante de l'instruction
else. Si l'on veut que l'instruction qui lui
est associée soit une instruction vide (ce qui peut sembler bizarre
car on peut alors se poser la question de l'utilité du else),
il faudra prévoir effectivement un ";" à la suite.
|
|
Les instructions if peuvent
être enchâssées. Dans
ce cas, si l'une ou plusieurs d'entre elles sont complétées
d'instructions else, il apparaît
souhaitable de connaître très précisément la
syntaxe afin d'éviter toute erreur d'interprétation dans
l'évaluation. Considérons, par exemple, l'écriture
suivante :
V1 = V2 = 12;
V3 = 16;
if (V1 >= V2)
if (V2 >= V3)
alert(V3 + ' n\'est pas strictement superieur a '
+ V1)
else
alert(V1 + ' est strictement inferieur a ' + V2)
|
Exec |
Étudiez ce programme. A priori il semble cohérent
avec le contenu des fenêtres alert qui sont prévues !....
Et pourtant !... Essayez de l'exécuter.
L'indentation qui a été choisie représentait ce que
l'utilisateur voulait signifier. En ce sens, effectivement, tout semble correct.
Le problème vient du fait que le else
se réfère au if le plus proche.
Un moyen simple de se rappeler de cela consiste à dire que if
est à else ce que la parenthèse
gauche est à la parenthèse droite, dans une expression
correctement parenthésée, bien sûr ! Et là apparaît
peut-être l'intérêt d'une instruction vide après
un else... Il est néanmoins préférable
d'utiliser la structure de bloc, ce qui donne :
V1 = V2 = 12;
V3 = 16;
if (V1 >= V2){
if (V2 >= V3)
alert(V3 + ' n\'est pas strictement superieur a '
+ V1)}
else
alert(V1 + ' est strictement inferieur a ' + V2)
|
|
|
Pour en terminer, nous allons présenter les if...else
en cascade, ce qui introduit la forme idiomatique plus connue du
else if. Nous avons vu que le if...else permettait sur la base du résultat
d'une expression booléenne d'obtenir deux actions exclusives l'une
de l'autre. Avec les else if, il est possible d'étendre le nombre de
sorties (d'actions exclusives). Supposons que la ligne de commande d'un éditeur
ligne puisse recevoir "I" pour Insert, "E" pour Exit,
"Q" pour Quit, "X" pour eXchange, etc. L'interpréteur
de commandes aura donc l'allure suivante ;
if (calu == 'I') <traitement
de Insert>
else if (calu == 'E') <traitement de Exit>
else if (calu == 'Q') <traitement
de Quit>
else if (calu == 'X') <traitement
de eXchange>
else
if....
|
|
|
Dans l'exemple que nous venons de donner, on constate que
l'écriture et la lisibilité deviennent problématiques
si le nombre de cas devient important. Mis à part des cas simples à
deux ou trois sorties, on préférera donc utiliser l'instruction
switch qui offre un formalisme simple et clair
quel que soit le nombre de cas envisagés. Sa syntaxe est la suivante
:
switch (<expression>)
{
case <valeur1> : <traitement
de valeur1> ;
case <valeur2> : <traitement
de valeur2> ;
......
[default : <traitement
autres cas> ;]
}
|
Remarques :
Le cas
default est optionnel. Il permet d'éviter
l'apparition d'une erreur lors d'une tentative de traitement d'un cas non
prévu. Dans une utilisation mettant en évidence des cas particuliers
par opposition à un cas général, default
prend toute son utilité.
Le traitement
associé à chaque cas doit assurer la sortie de l'instruction
switch. En fait un case
représente un accès d'entrée sur la base de la valeur
de l'expression, mais en aucun cas la rencontre séquentielle du case
suivant ne constitue une sortie de l'instruction switch.
En conséquence, sauf précaution particulière, le traitement
d'un cas particulier entraînera l'exécution des instructions
prévues pour celui-ci ainsi que toutes celles qui suivent. Afin d'interrompre
l'exécution, il conviendra de prévoir en dernière instruction
de chaque cas (sauf du dernier pour lequel le problème disparaît)
une rupture de séquence. Cela pourra être réalisé
par l'instruction break (que nous allons étudier
ensuite et dont le rôle et justement d'interrompre l'exécution
d'une boucle ou d'un aiguillage) ou l'instruction return
si le switch est dans une fonction, etc.
Exemple :
Les deux portions de programme ci-dessous ont un comportement identique.
if (Var != 5)
Var = Var + 12// ou Var+=12
else
Var = Var * 3 + 12; |
switch (Var) {
case 5 : Var = Var * 3;
default : Var = Var + 12;
} |
En effet, dans le cas où var
a pour valeur 5, l'exécution du switch
va successivement opérer var= var *3,
puis var = var +12 puisqu'il n'y a pas de
rupture de séquence après la première instruction. Dans
le cas où var est différent
de 5, seule l'instruction associée au default
va être exécutée. Le comportement est bien identique
au if... else de gauche.
ATTENTION :
Alors que l'on aurait pu remplacer Var=Var+12
par Var+=12 , le fait de substituer à
Var=Var*3+12 l'écriture Var*=3+12
aboutit à un résultat différent ! En effet, en vous
rapportant au tableau
des priorités d'opérateurs, vous constatez que *=
est moins prioritaire que +. Donc l'expression
Var*=3+12 est évaluée est en
fait comme Var=Var*(3+12).
|
2
- Les boucles
|
JavaScript, comme la plupart des langages de programmation,
comporte deux types de boucle : les boucles non bornées
et les boucles bornées.
Les premières sont celles dont on ne connaît
pas le nombre de fois qu'elles seront exécutées car le test
de fin de boucle est une expression booléenne mettant en jeu des informations
non connues, même de façon formelle, au moment de l'écriture
du programme.
Les autres sont celles pour lesquelles, au moment de la
rédaction du programme, on sait (au moins de façon formelle)
combien de fois elles doivent boucler (boucles muettes où la
valeur de l'indice de boucle peut n'avoir aucun
rôle dans les instructions qui en font partie) ou à quelle valeur
on doit commencer le calcul, à quelle valeur il se termine et quel
est le pas de variation entre chaque itération (boucles expressives
où la valeur d'indice a une fonction dans les calculs).
|
|
La première instruction de boucle non bornée est l'instruction
while dont la syntaxe est la suivante :
while
(<expression booléenne>)
<corps de boucle>
|
Le corps de boucle peut se réduire à une seule
instruction ou, au contraire, en comporter plusieurs. Dans ce cas, bien sûr,
le bloc sera délimité par { et
}. Comme pour les autres langages que vous
connaissez peut-être, le fonctionnement de la boucle while est le suivant
:
- Évaluation de l'expression booléenne d'entrée ;
- Si cette évaluation délivre la valeur false,
la boucle est terminée et l'exécution se poursuit en séquence
vers 4;
Si le résultat de l'évaluation est true,
le corps de boucle est exécuté.
- Retour en 1.
- Suite du programme.
En conséquence, une boucle while peut ne pas être exécutée
dans le cas où le test d'entrée s'avère toujours faux.
A contrario et comme dans tous les autres langages, la logique de programmation
réclame que si l'entrée dans la boucle est possible, l'environnement
servant à l'évaluation de l'expression booléenne subissent
une modification dans le corps de boucle, faute de quoi le programme sera
dans une boucle infinie.
|
|
La seconde instruction de boucle non bornée est le do/while
qui, pour les habitués de Pascal, correspond, d'un point de vue logique,
au repeat/until. Sa syntaxe est la suivante
:
do
<corps de boucle>
while
(<expression booléenne>);
|
Par rapport à l'instruction précédente,
il est évident de constater que cette boucle s'exécute au
moins une fois et ce n'est qu'après cette exécution qu'est
évaluée l'expression booléenne afin de déterminer
si la boucle doit être à nouveau exécutée ou
pas. Par rapport au repeat/until de Pascal,
on notera toutefois l'inversion du test puisqu'ici la boucle se maintient
tant que l'expression à une valeur true
alors qu'en Pascal le processus se réitère tant que l'expression
a une valeur false.
|
|
La boucle bornée est la boucle for
dont la syntaxe est décrite ci-dessous :
for([var]
<ident>=<init>;<test
de fin>;<opération>)
<corps de boucle>
|
Le fait de faire précéder l'identificateur
d'index de boucle du mot réservé var
est optionnel. Pour plus de détails revenir au §
I.1. La commande for se compose donc
de trois composants séparés par le caractère ";".
En premier lieu, on trouve l'affectation de la variable index de boucle
à sa valeur initiale. Ensuite, se situe une expression booléenne
évaluée avant d'entrer dans le corps et constituant un test
d'arrêt (effectif si son évaluation délivre la valeur
false). Enfin, le troisième élément
est une action effectuée au sortir du corps de boucle et permettant,
en règle générale, d'effectuer l'incrémentation
de l'index. Comme précédemment, le corps de boucle peut
soit se réduire à une seule instruction, soit, s'il en comporte
plusieurs, nécessiter leur encadrement par {
et } pour définir une structure
de bloc.
Voici donc un exemple simple d'une telle boucle dont vous pouvez obtenir
le résultat de l'exécution :
var S = "";
for(var I = 0 ; I < 10 ; I++)
S += I;
alert("La boucle a construit la chaine : " + S);
|
Exec
|
Mais au delà d'une telle utilisation "canonique", on peut
imaginer d'autres formes d'utilisations de la boucle for.
Voici un exemple qui va nous permettre de montrer à la fois comment
le pas d'incrémentation peut être quelconque (et en tout cas
différent de 1) et comment décrire un while
avec un for (on avait plutôt l'habitude
inverse). Voici l'exécution.
var arret = true, S = "", Add = 'abc';
alert("Je demarre");
for(var i = 1 ; arret ; i += 3){
alert("Dans for, i = " + i);
S += Add
arret = !(S.length > 8);
}
alert("J'en suis sorti !!!")
|
Exec |
On voit que l'incrément (ici, 3) a pu être
pris en compte grâce à l'opérateur +=. Quant au test d'arrêt,
on voit qu'il peut n'avoir aucun lien direct avec l'index. C'est en fait une
expression booléenne quelconque qui, d'une part est évaluée
avant l'entrée dans le corps de boucle, et, d'autre part, évaluée
à false provoque l'abandon de la boucle...
EXACTEMENT COMME POUR LE while !!!
Grâce aux opérateurs de pré ou post
incrémentation, dans le cas d'un pas de 1, l'incrémentation
peut être réalisée dans le test, laissant ainsi le troisième
argument libre pour réaliser une opération quelconque. Reprenons
l'avant dernier exemple... On peut le modifier comme suit et vérifier
que l'exécution reste inchangée
modulo une translation compréhensible des valeurs de début et
fin.
Var S = "";
for(var I = -1 ; I++ < 9 ; S += I)
alert("La boucle a construit la chaine : " + S);
|
Exec
|
En intégrant la post incrémentation dans le
troisième champ de l'instruction, les valeurs de début et fin
restaient inchangées... la preuve !
var S = "";
for(var I = 0 ; I < 10 ; S += I++);
alert("La boucle a construit la chaine : " + S);
|
Exec
|
Enfin, il convient de noter que l'opérateur ","
permet de multiplier le nombre de variables, de tests et/ou d'opérations
dans une boucle for. Il ne faut pas confondre
cette structure avec des boucles enchassées où chacune
gère une variable. Ici toutes les variables progressent simultanément.
Voici un exemple qui va nous servir à illustrer cela :
var S = "";
for(var I = 1 ; I < 6 ; I++)
for(var J = 2 ; J < 7 ; J +=2)
for(var K = 3 ; K < 8 ; K +=3)
S += "" + I + J + K;
alert("Chaine construite : " + S);
|
var S = "";
for(var I=1, J=2, K=3; I<6, J<7, K<8; I++, J+=2, K+=3)
S += "" + I + J + K;
alert("Chaine construite : " + S); |
Résultat
|
Résultat
|
Le résultat des boucles enchâssées
correspond bien à ce à que l'on attendait. I étant
initialisé à 1, J l'est à 2 tandis que K va balayer
toutes les valeurs de 3 à 7 par pas de 3 (soit 3 et 6) avant que
J ne passe à 4, etc. Pour la boucle multiple, les trois tests sont
évalués avant l'exécution du corps ; dès que
l'un d'eux est évalué à false,
la boucle est stoppée. Ici, la première boucle sera effectuée
pour I=1, J=2, K=3, la seconde pour I=2, J=4, K=6, mais la troisième
ne sera pas exécuté car bien que I (qui prend la valeur
3) et J (qui prend la valeur 6), soient bien dans les bornes autorisées,
K qui vaut à présent 9 met en défaut K<8.
|
|
La boucle for revêt
une autre forme adaptée à la structure objet. Sa syntaxe est
alors la suivante :
for([var]
<ident> in <objet>)
<corps de boucle>
|
La variable va énumérer tous les noms de propriétés
associées à l'objet référencé. Nous
avons utilisé de nombreuses fois ce type de boucle lorsque nous
avons abordé les objets au § II.7.
Nous allons en donner ici un rapide exemple qui va nous permettre d'énumérer
toutes les propriétés/méthodes contenues dans cette
fenêtre.
Var S = "Proprietes de window :\n";
for(var i in this) // ou
window
S += i + ", ";
alert(S);
|
Exec
|
On note au passage que i prend pour valeurs successives la chaîne
désignant le nom de la propriété et non la valeur.
Nous verrons dans le prochain chapitre traitant des objets, que pour obtenir
la valeur effective il faudra utiliser l'accès associatif à
l'objet... à l'exception du cas de l'objet window !!!
On notera aussi que les propriétés énumérées
contiennent celles introduites par le constructeur window, mais aussi
celles qui ont été rajoutées ensuite (fonctions
définies dans cette page, images, etc.)
|
3
- Les ruptures
|
Les ruptures de séquences
constituent un concept qui fut largement (trop peut-être) utilisé
dans les langages de programmation d'ancienne génération (Fortran,
Basic, Cobol, etc.) Ensuite sont apparus des langages de programmation structurée
tournant résolument le dos à cette notion (Algol W, Pascal,...).
Les langages récents (C, Java, JavaScript, Perl) réintroduisent
les ruptures de séquences utilisant, dans certains cas, des étiquettes
pour effectuer des sorties de blocs (boucles, fonctions, aiguillages).
|
|
La syntaxe des étiquettes suit celle des identificateurs
de JavaScript (voir §
II.1). La syntaxe est particulièrement simple. Il suffit de faire
précéder l'instruction que l'on désire étiqueter
par une étiquette suivie de :.
<ident
étiquette> : <instruction>
|
Nous avons déjà introduit auparavant des étiquettes
particulières. En effet case et default
apparaissant dans une instruction switch ont
un statut d'étiquettes. Bien que syntaxiquement on puisse étiqueter
n'importe quelle instruction, dans les faits, seules les boucles que nous
venons d'étudier seront concernées afin d'effectuer, soit des
abandons définitifs (break) soit des
abandons de l'itération en cours et passage à l'éventuelle
itération suivante (continue).
NB : goto est un
mot réservé de JavaScript, mais l'instruction correspondante
n'est pas reconnue du langage.
|
|
L'instruction break provoque
la sortie immédiate d'une instruction d'aiguillage (switch)
ou de la boucle dans laquelle elle apparaît (pas au-delà dans
le cas de boucles imbriquées). Hors de ces contextes, l'occurrence
de l'instruction break (seule) provoque
une erreur.
Si l'instruction break comporte
une étiquette, celle-ci doit impérativement désigner
une instruction d'un niveau supérieur à celui où apparaît
l'appel. Dans ce cas, c'est tout le bloc ainsi désigné qui sera
abandonné. A noter que contrairement au cas précédent,
le break étiqueté peut
être employé dans n'importe quel contexte définissant
de façon implicite ou explicite un bloc. On peut ainsi nommer,
par exemple, une instruction if ou de façon
plus générale une suite quelconque d'instructions encadrées
d'accolades même si celles-ci sont mises dans le seul but de nommer
la suite d'instructions qu'elles contiennent.
Voici un exemple mettant en jeu ce qui vient d'être
expliqué. Essayez de déterminer ce que va être la sortie
puis vérifiez.
var S = "Valeurs successives d'index
:\n";
Boucle1:for(var i = 0 ;i < 5; i++){
Boucle2:for(var j = 0; j < 6; j+=2){
if (j > 2) break;
if (i == 1) break Boucle2;
if (i == 4) break Boucle1;
S += "i = " + i + " j = " + j + "\n";
}
}
S += "En sortie : i = " + i + " j = " + j + "\n";
alert(S);
|
Exec
|
|
|
L'instruction continue comme
break, interrompt la boucle en cours. Mais,
alors que break termine définitivement la boucle, continue se contente
d'abandonner l'itération en cours pour passer directement à
celle qui suit. Cela impose donc, dans une boucle while
ou do/while, que l'environnement servant à
évaluer l'expression gérant la fin de boucle ait été
réactualisé avant l'exécution de l'instruction continue,
faute de quoi on sera en présence d'une boule infinie. Cette précaution
est sans objet dans une boucle for puisqu'après
une instruction continue, l'exécution
se poursuit vers l'incrémentation, dans un premier temps, avant de
procéder au test.
ATTENTION : Dans
Navigator 4, la condition du do/while n'est plus évaluée après
l'exécution de l'instruction continue, si bien que l'itération
suivante est lancée systématiquement !...
L'instruction continue peut donc apparaître dans le
corps d'une boucle while ou for ou encore for/in (l'utilisation dans un do/while
étant fortement déconseillée). Hors de ces contextes,
l'occurrence de l'instruction continue
provoque une erreur de syntaxe.
Tout comme l'instruction break
, continue peut être associée
à une étiquette, celle-ci devant impérativement désigner
une instruction d'un niveau supérieur à celui où apparaît
l'appel. Dans ce cas, c'est au niveau l'itération suivante de la boucle
ainsi désignée que se poursuivra l'exécution.
Voici un exemple mettant en jeu ce qui vient d'être
expliqué. Essayez de déterminer ce que va être la sortie
puis vérifiez.
Var S = "Valeurs successives d'index :\n";
Boucle:for(var i = 0 ;i < 4; i++){
for(var j = 0; j < 5; j+=2){
if (j == 2) continue;
if (i == 1) continue Boucle;
S += "i = " + i + " j = " + j + "\n";
}
}
S += "En sortie : i = " + i + " j = " + j + "\n";
alert(S);
|
Exec
|
|
4
- Préfixage d'objets
|
L'écriture induite par un langage objet peut devenir
lourde lorsqu'on désire, faire référence à une
propriété définie à un niveau très profond
dans la hiérarchie des objets. Par exemple, si on définit dans
le document contenu dans cette fenêtre, un formulaire contenant un champ
de texte dont la valeur est "Le lien ..." et que nous voulons remplacer
cette chaîne par le nom du lien qui va lui-même permettre de réaliser
cette opération, il faudra exécuter l'instruction suivante :
window.document.Formul.textfield.value = window.document.links[14];
Vous pouvez contrôler cela en observant la barre de
status au bas de votre fenêtre alors que la souris survole le
bouton de déclenchement...
...où ChgTxt est
une fonction JavaScript se résumant à l'instruction
ci-dessus. (Pourquoi 14 ?... Parce que je sais que c'est le
quinzième de cette page et que les indices de tableau débutent
en 0, tout simplement !!!)
En fait, pour les curieux qui vont vérifier
le source, il verront que pour le site "Developpez.com"
qui rajoute des liens dont je n'ai pas la maitrise, j'ai opéré
d'une autre manière.
|
|
L'exemple que nous venons de prendre, bien qu'il ne soit
pas particulièrement compliqué, va nous permettre, néanmoins,
de montrer l'utilité et le fonctionnement de l'instruction with.
Encore une fois, la syntaxe de cette instruction est particulièrement
simple :
with
(<objet>)
<corps de with>
|
Comme d'habitude, le corps de cette instruction peut se
limiter à une seule instruction ou peut en contenir plusieurs, auquel
cas, elles seront encadrées par { et
}. L'utilité de cette instruction est
de définir temporairement un objet standard tels que toutes
les références de propriétés de celui-ci apparaissant
dans le corps peuvent être résolues sans qu'il soit besoin dudit
objet. Ainsi, dans notre exemple précédent, nous aurions pu
écrire :
with
(window.document)
Formul.textfield.value = links[14];
|
L'intérêt est ici modeste, mais dans le cas
où le corps de l'instruction contient un nombre non négligeable
de références à l'objet mis en préfixe, on comprend
que cela puisse devenir intéressant. Il est évident que dans
le corps d'un with, pourront apparaître (et cela est heureux !...) des
variables n'ayant aucun lien avec l'objet standard (indices de boucles
ou autres). On en déduit donc que le préfixage n'interviendra
que lorsqu'il sera fait référence à une propriété
existante de cet objet.
Au risque d'anticiper sur le prochain chapitre traitant
spécifiquement des objets, supposons que pour un objet que nous appellerons
"Ordinateur" on ait déjà défini les propriétés
"Systeme", "Memoire" et "Disque", et que l'on
veuille leur affecter une valeur et rajouter une nouvelle propriété
: "Processeur". Considérons les deux portions de programme
suivantes :
with (Ordinateur){
S = "Proprietes de Ordinateur :\n";
Systeme = "WinXP";
Memoire = 1024;
Disque = 80000;
Processeur = "Pentium IV";
}
for (var i in Ordinateur)
S += i + " = " + Ordinateur[i] + ",\n";
alert(S);
|
with (Ordinateur){
S = "Proprietes de Ordinateur :\n";
Systeme = "WinXP";
Memoire = 1024;
Disque = 80000;
Ordinateur.Processeur = "Pentium IV";
}
for (var i in Ordinateur)
S += i + " = " + Ordinateur[i] + ",\n";
alert(S); |
Résultat
|
Résultat
|
On constate que dans le premier cas, la liste des propriétés
ne contient pas "Processeur". En fait, on a simplement défini
non pas une propriété de l'objet "Ordinateur", mais
une variable de type chaîne à laquelle on a affecté la
valeur "Pentium IV". De la même manière que S, par
exemple n'est pas, non plus, une propriété de ce même
objet. Dans le second cas, par contre, on a spécifié, bien qu'étant
dans le corps du with, Ordinateur.Processeur
= "Pentium IV". On vérifie que la propriété
a alors bien été rajoutée à l'objet.
|
5
- Les définitions de fonctions
|
L'instruction function de
JavaScript permet de définir un objet fonction en tant que propriété/méthode
de l'objet dans lequel il est défini. Sa syntaxe est la suivante :
function
<ident> ([<par1>
[,<par2> [...,
<parp>]...]){
<corps de function>
}
|
Dans cette syntaxe, il apparaît que les parenthèses
sont obligatoires (même s'il n'y a pas de paramètres), de même
que les accolades (même si le corps se réduit à une seule
instruction) à la différence de ce que nous avons vu précédemment
pour les corps de boucle.
Le fait de classer la définition des fonctions dans
les instructions se place sur le même plan que ce que nous verrons dans
le prochain paragraphe : ajout d'une propriété d'un objet contenant
; mais, comme dans les autres langages, la définition n'engendre pas
l'exécution. Vous pouvez même, si le coeur vous en dit, définir
une fonction dont les instructions ne seront jamais exécutées.
En fait, au chargement de la page, le code JavaScript est analysé,
puis ce qui est au niveau global est effectivement exécuté (c'est
ce qui a été appelé au §
I.5 fonctionnement synchrone). L'exécution d'une fonction,
et donc des instructions qu'elle contient, ne se fera que de façon
asynchrone par appel de ladite fonction. Cela va avoir des répercussions
surprenantes (dont il faudra tenir compte) sur l'exécution. Considérons
par exemple un document contenant le script suivant :
<script
language="JavaScript">
alert(Succ(6)); // Appel de
la fonction
alert(Succ); //
Affich de la fonction
Succ = 0;
function Succ(x) { // Définition
return x+1;
}
alert(Succ); //
Affich de la fonction ?
</script>
|
|
Le fait de cliquer sur le bouton Exec a provoqué l'ouverture d'une page
(vous l'avez peut-être aperçue au centre de l'écran). La
fonction Succ est donc une propriété de cette page (analyse au
chargement) qui va être utilisée puis modifiée par le script. |
6
- Les déclarations
|
Bien que nous ayons commencé ce cours par un paragraphe
introduisant la notion de variable JavaScript,
nous ne pouvions pas éviter d'en reparler dans ce chapitre car
la déclaration explicite d'une variable est effectivement une instruction
qui peut, comme on l'a vu, apparaître n'importe où dans un
script. On peut toutefois compléter ce qui a donc été
dit au §
I.1 en précisant que l'opérateur ","
va trouver un de ses emplois les plus fréquents dans ce type d'instruction.
En effet, la syntaxe générale est de la forme :
var <ident1>
[= <valeur1]
[, ....., <identp>
[= <valeurp>]....]
Avant d'en terminer, il convient de préciser que
le fait de définir une variable va avoir pour effet de la rajouter
en tant que propriété de l'objet qui la contient. Si c'est au
niveau global qu'elle est définie, ce sera une propriété
de l'objet window, si c'est dans une fonction,
ce sera une propriété de cet objet fonction, lui même
objet de window (si la fonction est définie
au niveau global)...
|
|
La latitude de déclarer ou pas de façon explicite des
variables peut avoir des conséquences éventuellement fâcheuses
sur l'exécution d'un programme. En effet, une déclaration
implicite, même si elle est opérée à l'intérieur
d'une fonction, se traduit par une déclaration au niveau le plus
haut. Si à ce niveau, une variable de même nom existe, elle
sera substituée par la nouvelle variable implicitement déclarée
et sa valeur sera donc affectée par les modifications survenues
au niveau inférieur. Pour bien comprendre cela regardons les résultats
obtenus par ces deux programmes où la seule différence réside
dans la déclaration de la variable i dans la fonction effectuée
soit de façon explicite, soit de façon implicite...
|
S="";
for(i=1;i<6;i++)
enumerer(i);
alert(S);
function enumerer(x){
for(var i=8;i<12 ;i++) //decl. explicite
S+="("+x+","+i+")";
S+="\n";
}
|
|
|
S="";
for(i=1;i<6;i++)
enumerer(i);
alert(S);
function enumerer(x){
for(i=8;i<12 ;i++) //decl. implicite
S+="("+x+","+i+")";
S+="\n";
}
|
|
|
|
|