Les variables permettent d'instancier un objet et de manipuler cette instance à l'aide d'un identificateur (le nom de la variable). Tous les identificateurs en JavaScript sont des références à un objet. Javascript étant un langage au typage dynamique, le type des objets n'est pas déclaré explicitement et il peut changer automatiquement.
Il est donc possible de déclarer une variable sans lui définir de type. Ou plutôt, une variable déclarée de telle manière sera du type undefined.
Tout au long de son utilisation, cette variable pourra changer de type sans que l'interpréteur n'y trouve rien à redire.
var ma_versatile; // est undefinedma_versatile = "Je deviens une chaîne"; // devient stringma_versatile = 5; // devient numberma_versatile = new Array(); // devient object
Il n'est en fait pas nécessaire de déclarer une variable (avec le mot-clévar). La différence est expliquée ci-après.
Les règles d'élaboration des identificateurs sont décrites àce lien.Pour résumer, les identificateurs comportent des caractères alphanumériques et le tiret soulignant (_). Ils ne peuvent commencer par un chiffre, et les majuscules comptent.
L'instanciation directe (sans mot-clé var) d'un objet avec un identificateur donne souvent l'impression de créer une variable globale. En réalité, la notion de "variable globale" n'existe pas en JavaScript. Toutes les variables sont, sauf quand on les déclare avecvar, des propriétés d'un objet. Par défaut, cet objet est implicitement l'objetwindow (et non,window n'est pas une variable globale qui ferait exception à la règle car il est une de ses propres propriétés, c'est-à-dire quewindow est une propriété dewindow).
Commewindow reste l'objet implicite la plupart du temps, une variable créée ainsi pourra être employée comme si elle était globale :
ma_variable = "une valeur";function maFonction(){ mon_autre_variable = "une autre valeur"}maFonction()alert(mon_autre_variable) // affiche "une autre valeur"La variable mon_autre_variable est certes déclarée dans une fonction, mais il faut lire "window.mon_autre_variable" donc c'est une propriété de window et elle ne sera pas détruite automatiquement à la fin de la fonction.
Pour économiser du code, il peut être intéressant de sous-entendre un autre objet quewindow. Cela se fait explicitement avec un blocwith. Cette déclaration ne fonctionne pas aussi simplement qu'en Basic, par exemple. L'objet est en fait placé en haut de lascope chain dans le bloc d'instruction, presque comme si ses propriétés étaient des variables locales d'une fonction (voirProgrammation JavaScript/Scope chain). Lorsqu'on utilise un identificateur dans un blocwith, la résolution se fait aussitôt qu'une des conditions suivantes est remplie :
Si aucune condition n'est remplie et que l'expression affecte une valeur à la variable, cette variable est créée comme propriété de l'objet global. Si l'expression ne fait qu'utiliser la valeur, elle retournera simplementundefined.
c=trued="propriété de window"monObjet={a:0,d:"propriété de monObjet"}with(monObjet){alert(a)// affiche la valeur de monObjet.a : "0"a=2// monObjet.a existe et va être utilisé// si on veut utiliser window.a, il faut le faire explicitementwindow.a=5b="texte"// b n'est encore défini nulle part donc window.b est créé// si on veut créer monObjet.b, il faut le faire explicitementmonObjet.b="autre chose"deletec// monObjet.c n'existe pas, mais window.c va être utiliséalert(d)// affiche "propriété de monObjet"// si on veut l'autre, il faut être explicitealert(window.d)// affiche "propriété de window"}
À l'aide de la déclarationvar, il est possible de définir une variable locale, qui n'est pas une propriété d'un autre objet. Cette déclaration peut avoir lieu n'importe où dans le corps d'une fonction, pas nécessairement au début, mais seules les utilisation ultérieures de l'identificateur feront référence à la variable locale puisqu'elle n'existait pas avant.
Comme toute variable locale, elle est automatiquement détruite à la fin de la fonction, bien que sa valeur puisse être sauvegardée dans certains cas (voirFermeture).Par contre, elle ne peut pas être détruite par l'opérateurdelete.
functionfoo(){varloc_1=2// n'a pas d'existence en dehors de foo()for(i=0;i<loc_1;i++){varloc_2=2*loc_1;// loc_2 est disponible pour toute la fonction foo()alert(loc_2);}alert(loc_2);// S'affiche sans problème}alert(loc_2);// Provoque une erreur
Si la déclarationvar est utilisée en-dehors de toute fonction, la variable sera utilisable dans tout le script.
L'exemple précédent montre l'effethositing (levage) des déclarations avec le mot-clévar.Les déclarations sont en effet remontées au niveau du premier bloc de code de la fonction.Cela permet dans l'exemple précédent de continuer à accéder à la variableloc_2 après la bouclefor.
Par contre, la partie initialisation n'est pas rehaussée et la variable a donc une valeur indéfinie (undefined).L'exemple précédent équivaut au code suivant :
functionfoo(){varloc_1;varloc_2;// Déclaration rehausséevari;// Déclaration impliciteloc_1=2;for(i=0;i<loc_1;i++){loc_2=2*loc_1;// loc_2 est disponible pour toute la fonction foo()alert(loc_2);}alert(loc_2);// S'affiche sans problème, vaudrait undefined si loc_1 <= 0}
Il en va de même pour les fonctions déclarées dans des fonctions :
functionadd(n){vart=addn(5);functionaddn(a)// ^^ déclaration rehaussée implicitement{returna+n;}returnt;}
Cela équivaut au code suivant :
functionadd(n){vart;functionaddn(a){returna+n;}t=addn(5);returnt;}
Depuis Javascript 5, le mot-clélet permet de déclarer des variables locales à un bloc, sans effet de rehaussement.
functionfoo(){letloc_1=2;for(i=0;i<loc_1;i++){letloc_2=2*loc_1;console.log(loc_2);}console.log(loc_2);// --> Uncaught ReferenceError: loc_2 is not defined}
Javascript est faiblement typé, mais typé quand même. Voici une revue des types que peut prendre une variable. Il est possible à tout moment de vérifier le type avec l'opérateurtypeof.
Une variable est du type undefined dans trois cas:
varmaNouvelleVar;// Déclarée mais pas affectéealert(typeofmaNouvelleVar);// Affiche undefined
undefined, ou qu'on lui affecte le résultat d'une expression qui retourne cette valeur.varjeSaisPas=undefinedvarcaNExistePas="impossible".enFrancaisalert(typeofjeSaisPas)// Affiche undefinedalert(typeofcaNExistePas)// Affiche undefined
alert(typeofvarPasDeclaree);// Affiche undefined (si elle n'a effectivement pas été affectée)monEphemere="exister";deletemonEphemere;// la vie est courtealert(typeofmonEphemere);// Affiche undefinedalert(varPasDeclaree)// erreur !!
À noter : dans les deux premiers cas, la variable existe et possède une valeur (undefined). On peut lire cette valeur sans provoquer d'erreur. Dans le troisième cas cependant, la variable n'existe pas : l'opérateurtypeof retourne "undefined", mais lire directement la valeur de la variable provoque une erreur.
JavaScript réunit en un seul type les entiers, petits et grands, les décimaux, et les réels, flottants ou pas.
r=1/3;alert(r);// affiche 0.333333333333alert(typeofr);// affiche numbern=4/2;alert(n);// affiche 2alert(typeofn);// affiche number3.6e5// 360 000 en notation scientifique0x40// 64 en notation hexadécimale0100// 64 en notation octale
Concrètement, les nombres sont stockés sur 64 bits, avec une mantisse de 53 bits. Cela permet des valeurs entières jusqu'à 9 007 199 254 740 991, à partir duquel on commence à perdre de la précision jusqu'à 2^1024-1 qui est la valeur flottante la plus élevée représentable en JavaScript.
En fait, JavaScript inclut également dans le typenumber deux valeurs spéciales.Infinity, un nombre signé, est renvoyé dès que le résultat dépasse la capacité de stockage denumber, mais aussi dans des cas limites simples. Dans les cas indécidables, ou bien lorsqu'une opération qui retourne un nombre ne peut pas le faire, c'est la valeurNaN (Not A Number) qui est renvoyée (voir lesopérateurs arithmétiques,les méthodes de Number etles méthodes de Math pour les cas qui produisent ces deux valeurs).
1/0==Infinity-2/Infinity==00/0==NaNNumber("texte")==NaN
Le typestring stocke une chaîne de caractères. C'est aussi le type le plus "faible" du langage : n'importe quelle valeur peut être convertie en chaîne, et en cas de doute avec l'opérateur+, c'est une concaténation qui aura lieu, pas une addition.
s = "Une chaîne de caractères";alert(typeof s); // Affiche "string"
Tous les objets possèdent une méthode générique toString() "magique" qui est appelée lorsqu'il faut convertir leur valeur en chaîne. Elle peut bien sûr être écrasée par une méthode plus spécifique.
Les chaînes de caractères en JavaScript sont encadrées par des guillemets droits (double quotes, ") ou dessingle quotes ('), au choix. Il n'y a pas de distinction entre des chaînes définies avec l'un ou l'autre, mais si on commence une chaîne par un type de guillemet il faut la finir par le même type. À l'intérieur d'une chaîne, les séquences d'échappement connues fonctionnent comme partout :
etc.
Enfin, JavaScript utilise des chaînes de caractères Unicode multi-octets. Quel que soit l'encodage du fichier où est écrit le script, il est toujours possible d'inclure n'importe quel caractère dans une chaîne, soit en récupérant une chaîne d'un autre fichier, soit en créant une chaîne avec la méthode statique String.fromCharCode(), soit en utilisant la séquence d'échappement :
Une variable de type boolean accepte deux valeurs : vrai et faux.
b=true;alert(typeofb);// Affiche "boolean"c=(5==3);// est faux, mais l'expression est booléenne.alert(typeofc);// Affiche "boolean"
Dans une comparaison, les valeurs suivantes sont équivalentes (opérateur==) àfalse :
Par ailleurs, les valeurs suivantes donnentfalse si on les convertit (explicitement ou pas) en booléen, bien qu'elle ne soient pas toutes équivalentes par comparaison :
Comme ces listes le montrent, une valeur peut être équivalente àfalse sans être considérée comme fausse elle-même ! Et inversement, une valeur considérée comme fausse n'est pas forcément équivalente au booléenfalse.
Cela peut sembler surprenant et illogique à première vue (et source de quelques bugs) mais il faut comprendre l'origine de ces différences :
Une valeur qui n'est pas équivalente àfalse ne sera pas pour autant équivalente àtrue par comparaison, à commencer parnull,NaN etundefined mais aussi toute valeur qui n'est pas équivalente à l'une des conversions possibles detrue (la chaîne "true", la chaîne ou le nombre 1).Par contre, toutes les valeurs qui ne donnent pasfalse par conversion enboolean donnenttrue, sans exception.
Attention, les valeurs de typeobject, y compris les instances des classesString,Number etBoolean créées avec le constructeurnew sont toujours converties entrue, même lorsque leur valeur est "", 0 oufalse (la seule exception estnull qui est de typeobject et dont la conversion en booléen estfalse). Cependant la comparaison avecfalse fonctionne de la même façon qu'avec des valeurs littérales.
Une variable de typeobject assume pleinement sa nature. Les autres types de variables, dits "scalaires", se comportent comme s'ils étaient eux-mêmes une valeur. Ainsi, lorsqu'on passe une variable scalaire à une expression, sa valeur est clonée. En revanche, passer une variable de typeobject ne fait que copier la référence, et la valeur n'est pas clonée.
L'existence de "classes" en JavaScript est discutée. Le langage ne possède pas de déclaration de classe en tant que telle. Pour cette raison, l'utilisation de ce terme sera mise entre guillemets.
Il existe trois manières de créer une variable de typeobject.
L'instanciation explicite d'un objet grâce à un constructeur s'effectue avecl'opérateurnew.
t=newArray();alert(typeoft)// Affiche "object"
Les expressions littérales de chaînes, nombres et booléens créent des variables scalaires alors que le constructeur de ces types crée un objet (explicitement de typeobject et donc strictement différents d'une valeur scalaire équivalente). Mais les expressions littérales de fonctions, tableaux et expressions rationnelles créent des objets, car ce ne sont pas des types scalaires. Ces objets, instanciés sans utilisation denew, sont néanmoins strictement identiques à leur équivalent produit par l'appel d'un constructeur. Par exemple :
// valeur scalaire vs. objet"chaîne"!==newString("chaîne")2.34!==newNumber(2.34)// objet vs. objet... c'est pareil !["a","b","c"]===newArray("a","b","c")/(\w+) ?\(/i===newRegExp("(\w+) ?\(","i")
On peut créer un objet générique (qui sera simplement une instance de la "classe"Object) avec la notation littérale. Cela consiste à écrire, entre accolades, une liste de couples clé : valeur séparés par des virgules, la clé pouvant être un identifiant ou bien une chaîne, et la valeur pouvant être n'importe quelle valeur. La clé et la valeur sont séparés par deux points (':').
objetLitteral={nom:"Mac OS X",version:10.5,"nom de code":"Leopard"}
Attention, dans l'exemple ci-dessus, on ne pourra accéder à la dernière propriété ("nom de code") de l'objet qu'avec la notation tableau (avec des crochets), pas la notation objet (avec des points) car ce n'est pas un identifiant valide (il y a des espaces dedans).
Le DOM (aussi bien W3C que IE) définit certaines "classes" : HTMLElement, HTMLTextNode, HTMLDocument, CSSRuleSet, CSSRule, etc. On doit utiliser les méthodes du DOM (comme document.createElement()) pour instancier ces objets (le "DOM 0" fait exception à cette règle et à bien d'autres).
Les autres "classes" d'objets ne peuvent être créés que par un constructeur. Il y a des constructeurs natifs tels queDate, et on peut définir un constructeur soi-même. Pour plus de détails, voir le chapitre consacré aux objets.
La différence essentielle entre une variable de type function et une variable de type object, est qu'on peut appeler une fonction. Dans les deux sens du terme :
Attention : ne pas confondre le type de variable ("object", "function") avec les constructeurs homonymes (Object,Function). Une variable de type "object" peut avoir n'importe quel constructeur sauf Function et bien des comportements différents, tous différents du comportement d'une fonction. Mais cette section est uniquement consacrée autype "function".
Contrairement aux autres types, le type "function" n'a pas de valeur spéciale (telle queNaN pour "number" ounull pour "object"). Il n'y a aucun moyen de convertir directement un autre type en fonction.
Une fonction est créée par l'expression littérale (exemple ci-dessous) ou bien par le constructeur Function.
functionfibonacci(n){if(isNaN(n)||n<0)returnundefinedn=Math.floor(n)varu=1,v=0while(n--)u=v+(v=u)returnv}
Cette déclaration crée une variable "fibonacci" qui référence la fonction, mais c'est aussi une opération qui retourne la référence de la fonction, que l'on peut ainsi affecter à une autre variable. Il est d'ailleurs possible de déclarer une fonction anonyme. De plus, toute nouvelle fonction reçoit automatiquement une propriétéprototype identique au prototype de la fonction Object.
L'appel se fait en ouvrant et fermant une paire de parenthèses juste après une expression dont la valeur est de type "function". Cette expression n'est pas obligatoirement le nom d'une fonction, ni même un identifiant. Cette signification des parenthèses est prioritaire sur la signification générale (forcer une expression à être évaluée avant celles qui l'entourent).
f=fibonaccideletefibonacci// efface seulement la variable, pas la fonction, qui est toujours référencée par fx=f(10);// Constitue l'appel de la fonction fibonacci, en lui passant un argumentalert(f)// affiche le code de la fonction, y compris le nom donné dans sa déclaration, "fibonacci"
Les opérateurs et méthodes qui acceptent des objets comme opérande ou argument fonctionnent pareil avec des fonctions, notamment le point pour accéder aux propriétés de la fonction.L'opérateurnew n'accepte que des fonctions comme opérande.
Par défaut, la conversion d'une fonction en chaîne retourne le code source de la fonction,préalablement reformaté par l'interpréteur JavaScript : les point-virgules, sauts de ligne et indentations seront normalisés.