web-dev-qa-db-fra.com

Déclaration de variables sans mot-clé var

Au w3schools, il est écrit:

Si vous déclarez une variable sans utiliser "var", la variable devient toujours GLOBAL.

Est-il utile de déclarer une variable globale dans la fonction? Je peux imaginer déclarer des variables globales dans un gestionnaire d’événements, mais à quoi servent-elles? Meilleure utilisation de la RAM?

40
xralf

Non, il n'y a aucun avantage RAM ou quelque chose comme ça.

Ce dont parle w3schools, c’est quelque chose que j’appelle L’horreur des globes implicites . Considérons cette fonction:

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}

Cela semble assez simple, mais il retourne NaN, pas 11, à cause de la faute de frappe sur la ligne varaible2 = 6;. Et cela crée une variable globale avec le nom typo'd:

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}
console.log(foo());     // NaN
console.log(varaible2); // 6?!?!?!

En effet, la fonction attribue à varaible2 (notez la faute de frappe), mais varaible2 n'est déclaré nulle part. Par le biais de la mécanique de la chaîne d’étendue en JavaScript, il s’agit d’une affectation implicite à une (nouvelle) propriété sur l’objet global (auquel vous pouvez accéder en tant que window sur les navigateurs).

C'est juste une "fonctionnalité" de JavaScript en mode souple, l'attribution d'un identifiant complètement non déclaré n'est pas une erreur; au lieu de cela, il crée un objet proprement dit sur l'objet global et les propriétés de l'objet global sont des variables globales. (Jusqu'à ES5, tous les globaux étaient des propriétés de l'objet global. À partir de ES2015, cependant, un nouveau type de global n'a pas été ajouté à la propriété de l'objet global. Global-scope let, const et class créent le nouveau genre de global.)

Mon exemple est une faute de frappe, mais bien sûr, vous pouvez le faire exprès si vous le souhaitez. C'est une partie clairement définie du langage, après tout. Alors:

myNewGlobal = 42;

... n'importe quel endroit où myNewGlobal n'est pas déclaré créera le nouveau global.

Mais je recommanderais vivement de ne jamais le faire à dessein: cela rend le code difficile à lire et à maintenir, et ce code sera incompatible avec les modules JavaScript lorsqu'ils seront plus courants et répandus. Si vous avez vraiment besoin de créer une variable globale à partir d’une fonction au moment de l’exécution (déjà un drapeau rouge, mais pour des raisons valables), faites-le explicitement en affectant une propriété sur window (ou tout ce qui fait référence à l’objet global de votre window sur les navigateurs):

window.myNewGlobal = 42;

En fait, je suggérerais d'utiliser le mode strict de ES5 . Le mode strict fait de l'attribution à un identifiant non déclaré une erreur plutôt que de créer silencieusement un global. Si nous utilisions le mode strict, le problème avec foo ci-dessus aurait été beaucoup plus facile à diagnostiquer:

"use strict"; // Turns on strict mode for this compilation unit

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;                 // <=== ReferenceError
    return variable1 + variable2;
}
console.log(foo());


Un peu tangentielle, mais en général, je recommanderais d'éviter les globals autant que possible. L'espace de noms global est déjà très encombré par les navigateurs. Le navigateur crée un global pour chaque élément du DOM avec un id, pour la plupart des éléments avec un name, et possède plusieurs globals prédéfinis (comme title) qui peuvent facilement entrer en conflit avec votre code.

Au lieu de cela, définissez vous-même une fonction de cadrage Nice et mettez-y vos symboles:

(function() {
    var your, symbols, here, if_they_need, to_be_shared, amongst_functions;

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

Et si vous faites cela, vous voudrez peut-être activer le mode strict:

(function() {
    "use strict";
    var your, symbols, here, if_they_need, to_be_shared, amongst_functions;

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

... qui, comme nous l'avons mentionné, présente l'avantage de transformer les assignations en identificateurs non déclarés en erreurs (avec diverses autres informations utiles ).

Notez que dans un JvaScript module (ajouté à ES2015, mais commence tout juste à trouver son chemin dans la nature), le mode strict est activé par défaut. (C'est également le cas des définitions class, également nouvelles dans ES2015.)

79
T.J. Crowder

Effets secondaires en oubliant var

Il existe une légère différence entre les globales implicites et celles définies explicitement .. La différence réside dans la possibilité de définir ces variables à l’aide de l’opérateur delete:

• Les globales créées avec var (celles créées dans le programme en dehors de toute fonction) Ne peuvent pas être supprimées.

• Les globales implicites créées sans var (peu importe si elles sont créées dans des fonctions) peuvent être supprimées

Cela montre que les globales implicites ne sont techniquement pas des variables réelles, mais des propriétés De l'objet global. Les propriétés peuvent être supprimées avec l’opérateur delete alors que les variables .__ ne peuvent pas:

// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
   global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"

En mode strict ES5, les affectations à des variables non déclarées (telles que les deux anti-modèles dans l'extrait précédent) génèrent une erreur.

JavaScript Patterns, de Stoyan Stefanov (O’Reilly). Copyright 2010 Yahoo !, Inc., 9780596806750.

16
user278064

La seule utilisation des variables globales est si vous devez y accéder globalement. Dans ce cas, vous devez les déclarer en utilisant le mot clé var en dehors des fonctions, afin d'indiquer clairement que vous souhaitez réellement créer des variables globales, sans oublier la var lorsque vous tentez de déclarer une variable locale.

En règle générale, vous devriez essayer d'étendre votre code afin que vous ayez besoin du moins possible dans l'étendue globale. Plus vous utilisez de variables globales dans votre script, moins vous pourrez l’utiliser avec un autre script.

Normalement, les variables d'une fonction doivent être locales, afin qu'elles disparaissent lorsque vous quittez la fonction.

3
Guffa

Parfois, il est utile de créer de nouvelles propriétés globalement accessibles à l’intérieur de fonctions facilement accessibles en référençant l’objet window (toutes les propriétés déclarées globalement sont attachées à l’objet window).

Cependant, comme c'est généralement le cas lorsque tout élément est déclaré accessible globalement, cela peut poser des problèmes plus tard, car ces propriétés peuvent être facilement écrasées, etc. Il est bien mieux de simplement passer des valeurs à des fonctions en tant qu'arguments et d'extraire leurs résultats.

2
brezanac

Déclarer une variable à l'intérieur d'une fonction sans utiliser var, let ou const n'est pas plus utile à l'intérieur de la fonction que déclarer cette variable avec var, let ou const. Et, comme indiqué dans les réponses précédentes à cette question, les déclarations globales implicites au niveau fonction locale peuvent être source de confusion et poser problème en dehors du champ de la fonction où elles ont été déclarées.

J'aimerais parler de quelques subtilités qui manquent dans la citation de w3schools et dans les réponses précédentes à cette question.

Tout d’abord, si vous n’appelez jamais la fonction qui génère des globales implicites, vous ne générerez pas de globales implicites. C'est une différence subtile par rapport à la citation w3schools car elle défie la section "toujours" de leur déclaration. 

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
}

// before calling the generateImplicitGlobals function, we can safely see that the x and y properties of the window object are both undefined:
console.log("before calling the generateImplicitGlobals function, properties x and y of the window object are: " + window.x + " and " + window.y);

// before calling the generateImplicitGlobals function, we can test for the existence of global variables x and y; note that we get errors instead of undefined for both.
try{
  console.log("before calling the generateImplicitGlobals function, x is: " + x);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference some global variable x produces " + e);
}

try{
  console.log("before calling the generateImplicitGlobals function, y is: " + y);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference the global variable b also produces " + e);
}
Certes, je suis sûr que w3schools est conscient du fait que la déclaration globale implicite dans une fonction n'est pas faite avant que la fonction ne soit appelée, mais, pour les utilisateurs novices en JavaScript, il se peut que cela ne soit pas clair. informations données.

En ce qui concerne les subtilités des réponses précédentes, une fois que la fonction generateImplicitGlobals a été appelée, nous pouvons voir que les tentatives d’accès à la propriété window.x ou à la variable globale x renvoient les mêmes valeurs (et que la propriété window.y et la variable globale y retournent). les mêmes valeurs). Ces instructions sont vraies lorsqu'elles sont appelées de l'intérieur ou de l'extérieur de la fonction generateImplicitGlobals.

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
  console.log("inside the function, x and window.x are: " + x + " and " + window.x);
  console.log("inside the function, y and window.y are: " + y + " and " + window.y);
}

// now, call the generator, and see what happens locally and globally.
generateImplicitGlobals();
console.log("after calling the generateImplicitGlobals function, x, window.x, y, and window.y are: " + x + ", " + window.x + ", " + y + ", and " + window.y);

1
Ed_Johnsen

Le problème principal est que quelqu'un d'autre utilise peut-être déjà un fichier global portant le même nom.

Ensuite, lorsque vous modifiez la valeur du global, vous écrasez leur valeur.

Plus tard, lorsque le global sera utilisé, il aura mystérieusement changé.

1
QuentinUK

Je dirais que cela pourrait nuire à votre sécurité et même à la stabilité de votre code.

Comme mentionné ci-dessus, vous pouvez vous tromper en orthographiant simplement vos variables. Le mot clé "use strict"; est le solution.
Avec ce mot clé déclaré, une erreur est générée: Uncaught ReferenceError: foo is not defined

Il fait également référence à un code sécurisé: 
1. Lors de l'écriture d'un code sécurisé, nous ne voulons pas que nos variables soient accessibles ailleurs que là où elles ont été déclarées. Ne déclarez pas de variables globales sans le besoin.
2. Lisez toujours attentivement les avertissements et résolvez-les. Utilisez "use strict";, JSlint et d'autres outils pour voir et résoudre les avertissements afin d'améliorer votre code.

0
Erik Rybalkin