Cet article est destiné à comprendre les anciens scripts
Les informations contenues dans cet article sont utiles pour comprendre les anciens scripts.
Ce n'est pas ainsi que nous écrivons du nouveau code.
Dans le tout premier chapitre sur les variables, nous avons mentionné trois manières de déclarer des variables :
let
const
var
La déclaration var
est similaire à let
. La plupart du temps, nous pouvons remplacer let
par var
ou vice-versa et nous attendre à ce que les choses fonctionnent :
var message = "Bonjour" ; alerte (message); // Salut
Mais intérieurement, var
est une bête très différente, qui vient de temps très anciens. Il n'est généralement pas utilisé dans les scripts modernes, mais se cache toujours dans les anciens.
Si vous ne prévoyez pas de respecter de tels scripts, vous pouvez même sauter ce chapitre ou le reporter.
D'un autre côté, il est important de comprendre les différences lors de la migration d'anciens scripts de var
vers let
, pour éviter des erreurs étranges.
Les variables, déclarées avec var
, ont une portée fonctionnelle ou globale. Ils sont visibles à travers les blocs.
Par exemple:
si (vrai) { var test = vrai ; // utilise "var" au lieu de "let" } alerte(test); // vrai, la variable vit après si
Comme var
ignore les blocs de code, nous avons une variable globale test
.
Si nous utilisions let test
au lieu de var test
, alors la variable ne serait visible à l'intérieur if
:
si (vrai) { laissez test = vrai ; // utilise "laisser" } alerte(test); // ReferenceError : le test n'est pas défini
La même chose pour les boucles : var
ne peut pas être local en bloc ou en boucle :
pour (var je = 0; je < 10; je++) { var un = 1 ; //... } alerte(i); // 10, "i" est visible après la boucle, c'est une variable globale alerte (un); // 1, "one" est visible après la boucle, c'est une variable globale
Si un bloc de code se trouve à l'intérieur d'une fonction, alors var
devient une variable au niveau de la fonction :
fonction direSalut() { si (vrai) { var phrase = "Bonjour" ; } alerte(phrase); // travaux } disBonjour(); alerte(phrase); // ReferenceError : la phrase n'est pas définie
Comme nous pouvons le voir, var
perce if
, for
ou d'autres blocs de code. C'est parce qu'il y a longtemps en JavaScript, les blocs n'avaient pas d'environnement lexical, et var
en est un vestige.
Si nous déclarons la même variable avec let
deux fois dans la même portée, c'est une erreur :
laisser l'utilisateur ; laisser l'utilisateur ; // SyntaxError : 'user' a déjà été déclaré
Avec var
, nous pouvons redéclarer une variable un certain nombre de fois. Si nous utilisons var
avec une variable déjà déclarée, elle est simplement ignorée :
var utilisateur = "Pete"; var utilisateur = "Jean" ; // cette "var" ne fait rien (déjà déclarée) // ...ça ne déclenche pas d'erreur alerte (utilisateur); // John
Les déclarations var
sont traitées au démarrage de la fonction (ou au démarrage du script pour les globales).
En d'autres termes, les variables var
sont définies depuis le début de la fonction, peu importe où se trouve la définition (en supposant que la définition ne soit pas dans la fonction imbriquée).
Donc ce code :
fonction direSalut() { phrase = « Bonjour » ; alerte(phrase); expression var ; } disBonjour();
… Est techniquement la même chose que ceci ( var phrase
déplacée ci-dessus) :
fonction direSalut() { expression var ; phrase = « Bonjour » ; alerte(phrase); } disBonjour();
…Ou même comme ceci (rappelez-vous, les blocs de code sont ignorés) :
fonction direSalut() { phrase = « Bonjour » ; // (*) si (faux) { expression var ; } alerte(phrase); } disBonjour();
Les gens appellent également un tel comportement « hissing » (augmentation), car toutes var
sont « hissées » (élevées) au sommet de la fonction.
Ainsi, dans l'exemple ci-dessus, la branche if (false)
ne s'exécute jamais, mais cela n'a pas d'importance. La var
à l'intérieur est traitée au début de la fonction, donc au moment de (*)
la variable existe.
Les déclarations sont levées, mais pas les affectations.
Cela est mieux démontré avec un exemple :
fonction direSalut() { alerte(phrase); var phrase = "Bonjour" ; } disBonjour();
La ligne var phrase = "Hello"
contient deux actions :
Déclaration de variable var
Affectation des variables =
.
La déclaration est traitée au début de l'exécution de la fonction (« hissée »), mais l'affectation fonctionne toujours à l'endroit où elle apparaît. Le code fonctionne donc essentiellement comme ceci :
fonction direSalut() { expression var ; // la déclaration fonctionne au début... alerte(phrase); // non défini phrase = « Bonjour » ; // ...affectation - lorsque l'exécution l'atteint. } disBonjour();
Étant donné que toutes les déclarations var
sont traitées au début de la fonction, nous pouvons les référencer à n'importe quel endroit. Mais les variables ne sont pas définies jusqu'aux affectations.
Dans les deux exemples ci-dessus, alert
s'exécute sans erreur, car la phrase
variable existe. Mais sa valeur n'est pas encore attribuée, elle affiche donc undefined
.
Dans le passé, comme il n'existait que var
et qu'il n'avait pas de visibilité au niveau des blocs, les programmeurs ont inventé un moyen de l'émuler. Ce qu’ils ont fait s’appelait « expressions de fonction immédiatement invoquées » (en abrégé IIFE).
Ce n'est pas quelque chose que nous devrions utiliser de nos jours, mais vous pouvez les trouver dans d'anciens scripts.
Un IIFE ressemble à ceci :
(fonction() { var message = "Bonjour" ; alerte (message); // Bonjour })();
Ici, une expression de fonction est créée et immédiatement appelée. Le code s'exécute donc immédiatement et possède ses propres variables privées.
L'expression de fonction est entourée de parenthèses (function {...})
, car lorsque le moteur JavaScript rencontre "function"
dans le code principal, il la comprend comme le début d'une déclaration de fonction. Mais une déclaration de fonction doit avoir un nom, donc ce type de code donnera une erreur :
// Essaie de déclarer et d'appeler immédiatement une fonction function() { // <-- SyntaxError : Les instructions de fonction nécessitent un nom de fonction var message = "Bonjour" ; alerte (message); // Bonjour }();
Même si nous disons : « ok, ajoutons un nom », cela ne fonctionnera pas, car JavaScript ne permet pas d'appeler immédiatement les déclarations de fonction :
// erreur de syntaxe à cause des parenthèses ci-dessous fonction aller() { }(); // <-- ne peut pas appeler la déclaration de fonction immédiatement
Ainsi, les parenthèses autour de la fonction sont une astuce pour montrer à JavaScript que la fonction est créée dans le contexte d'une autre expression, et qu'il s'agit donc d'une expression de fonction : elle n'a pas besoin de nom et peut être appelée immédiatement.
Il existe d'autres moyens que les parenthèses pour indiquer à JavaScript que nous entendons une expression de fonction :
// Façons de créer IIFE (fonction() { alert("Parenthèses autour de la fonction"); })(); (fonction() { alert("Parenthèses autour du tout"); }()); !fonction() { alert("L'opérateur Bitwise NOT démarre l'expression"); }(); +fonction() { alert("Unaire plus démarre l'expression"); }();
Dans tous les cas ci-dessus, nous déclarons une expression de fonction et l'exécutons immédiatement. Notons encore : de nos jours, il n'y a aucune raison d'écrire un tel code.
Il existe deux différences principales entre var
et let/const
:
Les variables var
n'ont pas de portée de bloc, leur visibilité est limitée à la fonction actuelle, ou globale, si elle est déclarée en dehors de la fonction.
Les déclarations var
sont traitées au démarrage de la fonction (démarrage du script pour les globales).
Il existe une autre différence très mineure liée à l'objet global, que nous aborderons dans le chapitre suivant.
Ces différences rendent var
pire que let
la plupart du temps. Les variables au niveau du bloc sont une très bonne chose. C'est pourquoi let
a été introduit dans la norme il y a longtemps et constitue désormais un moyen majeur (avec const
) de déclarer une variable.