Y a-t-il une différence entre déclarer une variable:
var a=0; //1
...par ici:
a=0; //2
...ou:
window.a=0; //3
à portée mondiale?
Y a-t-il une différence entre déclarer une variable:
var a=0; //1
...par ici:
a=0; //2
...ou:
window.a=0; //3
à portée mondiale?
Réponses:
Oui, il y a quelques différences, bien qu'en termes pratiques, ce ne sont généralement pas de grandes différences.
Il y a une quatrième façon, et depuis ES2015 (ES6) il y en a deux autres. J'ai ajouté la quatrième voie à la fin, mais j'ai inséré les voies ES2015 après # 1 (vous verrez pourquoi), nous avons donc:
var a = 0; // 1
let a = 0; // 1.1 (new with ES2015)
const a = 0; // 1.2 (new with ES2015)
a = 0; // 2
window.a = 0; // 3
this.a = 0; // 4
#1 var a = 0;
Cela crée une variable globale qui est également une propriété de l' objet global , auquel nous accédons comme windowsur les navigateurs (ou via thisune portée globale, en code non strict). Contrairement à certaines autres propriétés, la propriété ne peut pas être supprimée via delete.
En termes de spécification, il crée une liaison d'identifiant sur l' enregistrement d'environnement d' objet pour l' environnement global . Cela en fait une propriété de l'objet global car l'objet global est l'endroit où se trouvent les liaisons d'identifiants pour l'enregistrement d'environnement de l'objet de l'environnement global. C'est pourquoi la propriété n'est pas supprimable: ce n'est pas simplement une propriété simple, c'est une liaison d'identifiant.
La liaison (variable) est définie avant l'exécution de la première ligne de code (voir «Quand vararrive» ci-dessous).
Notez que sur IE8 et versions antérieures, la propriété créée sur windown'est pas énumérable (n'apparaît pas dans les for..ininstructions). Dans IE9, Chrome, Firefox et Opera, c'est énumérable.
# 1.1 let a = 0;
Cela crée une variable globale qui n'est pas une propriété de l'objet global. C'est une nouveauté depuis ES2015.
En termes de spécification, il crée un identifiant liant l' enregistrement d'environnement déclaratif pour l'environnement global plutôt que l' objet d' environnement. L'environnement mondial est unique en ayant une division Environnement Record, un pour tous les vieux trucs qui se passe l'objet global (l' objet de l' environnement Record) et un autre pour toutes les nouveautés ( let, constet les fonctions créées par class) qui ne sont pas allez sur l'objet global.
La liaison est créée avant l'exécution de tout code étape par étape dans son bloc englobant (dans ce cas, avant l'exécution de tout code global), mais elle n'est accessible en aucune façon jusqu'à ce que l'exécution étape par étape atteigne l' letinstruction. Une fois que l'exécution atteint l' letinstruction, la variable est accessible. (Voir "Quand letet constarriver" ci-dessous.)
# 1.2 const a = 0;
Crée une constante globale, qui n'est pas une propriété de l'objet global.
constest exactement comme letsauf que vous devez fournir un initialiseur (la = valuepartie), et vous ne pouvez pas changer la valeur de la constante une fois qu'elle est créée. Sous les couvertures, c'est exactement comme letmais avec un drapeau sur la liaison d'identifiant disant que sa valeur ne peut pas être modifiée. L'utilisation constfait trois choses pour vous:
# 2 a = 0;
Cela crée implicitement une propriété sur l'objet global . Comme il s'agit d'une propriété normale, vous pouvez la supprimer. Je recommanderais de ne pas le faire, cela peut ne pas être clair pour quiconque lira votre code plus tard. Si vous utilisez le mode strict d'ES5, cela (assignation à une variable inexistante) est une erreur. C'est l'une des nombreuses raisons d'utiliser le mode strict.
Et fait intéressant, toujours sur IE8 et versions antérieures, la propriété créée n'est pas énumérable (n'apparaît pas dans les for..ininstructions). C'est étrange, en particulier compte tenu du n ° 3 ci-dessous.
# 3 window.a = 0;
Cela crée une propriété sur l'objet global explicitement, en utilisant le windowglobal qui fait référence à l'objet global (sur les navigateurs; certains environnements non-navigateur ont une variable globale équivalente, comme globalsur NodeJS). Comme il s'agit d'une propriété normale, vous pouvez la supprimer.
Cette propriété est énumérable, sur IE8 et versions antérieures, et sur tous les autres navigateurs que j'ai essayés.
# 4 this.a = 0;
Exactement comme # 3, sauf que nous référençons l'objet global à la thisplace du global window. Cela ne fonctionnera pas en mode strict, cependant, car en code global en mode strict, thisn'a pas de référence à l'objet global (il a la valeur à la undefinedplace).
Qu'est-ce que j'entends par «supprimer» ou «supprimer» a? Exactement cela: Suppression de la propriété (entièrement) via le deletemot clé:
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
deletesupprime complètement une propriété d'un objet. Vous ne pouvez pas faire cela avec des propriétés ajoutées windowindirectement via var, le deleteest soit ignoré silencieusement, soit lève une exception (selon l'implémentation JavaScript et si vous êtes en mode strict).
Avertissement : IE8 à nouveau (et probablement plus tôt, et IE9-IE11 en mode "compatibilité" interrompu): il ne vous permettra pas de supprimer les propriétés de l' windowobjet, même si vous y êtes autorisé. Pire, il lève une exception lorsque vous essayez ( essayez cette expérience dans IE8 et dans d'autres navigateurs). Donc, lors de la suppression de l' windowobjet, vous devez être sur la défensive:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
Cela essaie de supprimer la propriété, et si une exception est levée, elle fait la meilleure chose suivante et définit la propriété undefined.
Cela ne s'applique qu'à l' windowobjet, et uniquement (pour autant que je sache) à IE8 et versions antérieures (ou IE9-IE11 en mode "compatibilité" interrompu). Les autres navigateurs acceptent de supprimer des windowpropriétés, sous réserve des règles ci-dessus.
vararriveLes variables définies par la vardéclaration sont créées avant tout le code étape par étape dans le contexte d'exécution est exécuté, et donc la propriété existe bien avant la vardéclaration.
Cela peut être déroutant, alors jetons un coup d'œil:
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
Exemple en direct:
Comme vous pouvez le voir, le symbole fooest défini avant la première ligne, mais pas le symbole bar. Où est l' var foo = "f";instruction, il y a vraiment deux choses: la définition du symbole, qui se produit avant l'exécution de la première ligne de code; et faire une affectation à ce symbole, ce qui se produit là où la ligne se trouve dans le flux pas à pas. C'est ce que l'on appelle le " varlevage" car la var foopièce est déplacée ("hissée") vers le haut de l'oscilloscope, mais la foo = "f"pièce est laissée à son emplacement d'origine. (Voir Poor incomprisvar sur mon petit blog anémique.)
letet constarriverletet constsont différents de varplusieurs façons. La manière qui est pertinente pour la question est que, bien que la liaison qu'ils définissent soit créée avant l'exécution de tout code étape par étape, elle n'est pas accessible tant que l' instruction letor constn'est pas atteinte.
Donc, pendant que cela fonctionne:
display(a); // undefined
var a = 0;
display(a); // 0
Cela génère une erreur:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
Les deux autres façons qui diffèrent letet qui ne sont pas vraiment pertinentes pour la question sont les suivantes:constvar
vars'applique toujours à l'ensemble du contexte d'exécution (dans tout le code global ou dans le code de fonction dans la fonction où il apparaît), mais letet consts'applique uniquement dans le bloc où ils apparaissent. Autrement dit, vara une portée de fonction (ou globale), mais letet consta une portée de bloc.
La répétition var adans le même contexte est inoffensive, mais si vous avez let a(ou const a), avoir un autre let aou un const aou un var aest une erreur de syntaxe.
Voici un exemple qui démontre cela letet constprend effet immédiatement dans son bloc avant l'exécution de tout code à l'intérieur de ce bloc, mais n'est pas accessible avant l' instruction letor const:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Notez que le second console.logéchoue, au lieu d'accéder à l' aextérieur du bloc.
window)L' windowobjet devient très, très encombré de propriétés. Dans la mesure du possible, je vous recommande fortement de ne pas ajouter au mess. Au lieu de cela, enveloppez vos symboles dans un petit paquet et exportez au plus un symbole vers l' windowobjet. (Je n'exporte souvent aucun symbole vers l' windowobjet.) Vous pouvez utiliser une fonction pour contenir tout votre code afin de contenir vos symboles, et cette fonction peut être anonyme si vous le souhaitez:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
Dans cet exemple, nous définissons une fonction et la faisons exécuter immédiatement (le ()à la fin).
Une fonction utilisée de cette manière est souvent appelée fonction de cadrage . Les fonctions définies dans la fonction de portée peuvent accéder aux variables définies dans la fonction de portée parce qu'elles sont des fermetures sur ces données (voir: Les fermetures ne sont pas compliquées sur mon petit blog anémique).
window['a']=0pour qu'il soit clair que j'utilise la fenêtre comme carte? est windowspécial de telle sorte que certains navigateurs ne le permettent pas et me forcent à utiliser window.a?
window.a = 0;ne fonctionne que dans les environnements de navigateur, et uniquement par convention. La liaison de l'objet global à une variable nommée windown'est pas dans la spécification ES et ne fonctionnera donc pas dans, par exemple, V8 ou Node.js, tandis que this.a = 0;(lorsqu'elle est invoquée dans le contexte d'exécution global) fonctionnera dans n'importe quel environnement puisque la spécification ne spécifie pas qu'il doit y avoir un objet global. Si vous encapsulez votre code dans un IIFE comme dans la section Hors sujet , vous pouvez passer en thistant que paramètre nommé windowou globalpour obtenir une référence directe à l'objet global.
var a = 0;devient automatiquement une propriété de l'objet global. Si je déclare var b = 0;dans une déclaration de fonction, sera-t-elle également une propriété d'un objet sous-jacent?
Garder les choses simples:
a = 0
Le code ci-dessus donne une variable de portée globale
var a = 0;
Ce code donnera une variable à utiliser dans la portée actuelle, et en dessous
window.a = 0;
Il s'agit généralement de la variable globale.
a sous le portée actuelle. Vous pouvez. De plus, votre utilisation de "variable globale" est un peu décalée - les deux endroits où vous dites "variable globale" ne sont pas plus globaux que l'endroit où vous ne le dites pas.
<title>Index.html</title>
<script>
var varDeclaration = true;
noVarDeclaration = true;
window.hungOnWindow = true;
document.hungOnDocument = true;
</script>
<script src="external.js"></script>
/* external.js */
console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8
console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!) *I personally find this more clugy than hanging off window obj
Existe-t-il un objet global dont tous les vars sont suspendus par défaut? par exemple: «déclaration globals.noVar»
window.*déclaration. Cette déclaration semble plus sûre contre le copier-coller de votre code, et claire également.
Bassed sur l'excellente réponse de TJ Crowder : ( Hors sujet: éviter l'encombrementwindow )
Voici un exemple de son idée:
Html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
</script>
<script src="script.js"></script>
</head>
<body>
<h1>Hello !</h1>
</body>
</html>
init.js (Basé sur cette réponse )
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
script.js
// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);
alert(a);
Voici le plnkr . J'espère que ça aide!
À l'échelle mondiale, il n'y a pas de différence sémantique.
Mais vous devriez vraiment éviter a=0puisque vous définissez une valeur sur une variable non déclarée.
Utilisez également des fermetures pour éviter de modifier la portée globale du tout
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
Toujours utiliser des fermetures et toujours hisser à portée mondiale lorsque cela est absolument nécessaire. Vous devez de toute façon utiliser la gestion des événements asynchrones pour la plupart de vos communications.
Comme @AvianMoncellor l'a mentionné, il existe un bogue IE qui var a = foone déclare qu'une portée globale pour le fichier. Il s'agit d'un problème avec l'interprète cassé notoire d'IE. Ce bug semble familier, donc c'est probablement vrai.
Alors respectez window.globalName = someLocalpointer
deleteun var).
var. Ce sont juste des mécanismes complètement différents qui ont à peu près le même résultat pratique. :-)
varsaute au bout de la portée.