«Var» ou pas de «var» dans la boucle «for-in» de JavaScript?

99

Quelle est la bonne façon d'écrire une for-inboucle en JavaScript? Le navigateur ne se plaint pas de l'une ou l'autre des deux approches que je montre ici. Tout d'abord, il y a cette approche où la variable d'itération xest explicitement déclarée:

for (var x in set) {
    ...
}

Et alternativement cette approche qui se lit plus naturellement mais ne me semble pas correcte:

for (x in set) {
    ...
}
futlib
la source
Tout est tombé sur ce poste lors du dépannage d' un fichier paquet généré webpack a été à l' origine d' erreurs à une boucle où varn'a pas été utilisé pour déclarer la iterator i: Uncaught ReferenceError: i is not defined. Je vais donc l'utiliser à partir de maintenant: / webpack traite les variables "globales" bizarrement, pour en savoir plus, voir: stackoverflow.com/a/40416826
user1063287

Réponses:

103

Utilisez var, cela réduit la portée de la variable, sinon la variable recherche la fermeture la plus proche à la recherche d'une varinstruction. S'il ne trouve pas de, varalors il est global (si vous êtes dans un mode strict using strict, les variables globales génèrent une erreur). Cela peut entraîner des problèmes tels que les suivants.

function f (){
    for (i=0; i<5; i++);
}
var i = 2;
f ();
alert (i); //i == 5. i should be 2

Si vous écrivez var idans la boucle for, l'alerte s'affiche 2.

Scoping et levage JavaScript

Gabriel Llamas
la source
4
Ne répond pas à la question, c'est pour une boucle for normale, pas pour for in.
IllidanS4 veut que Monica revienne
La raison pour laquelle i == 5 n'est-elle pas plus due au levage qu'au manque de var dans la boucle for?
Snekse
1
Un autre aspect important de ceci est que le mode strict interdit la création implicite de propriétés globales, donc l'utilisation de la boucle standard "for in" sans l'instruction var échouera et renverra une ReferenceError.
dkugappi
2
Mais, venant de Java, mettre l' varintérieur de la fortête ressemble à un local dans la boucle for, ce qui n'est pas le cas. Par conséquent, je préfère le style de user422039 ci-dessous.
njlarsson
2
Que faire si vous avez plus d'une boucle for dans une portée? Vous devrez soit réutiliser l'index (pas de var), soit déclarer beaucoup de nouvelles variables (j, k, l, m,…) que vous n'utiliserez plus jamais.
armin
40

La première version:

for (var x in set) {
    ...
}

déclare une variable locale appelée x. La deuxième version:

for (x in set) {
    ...
}

ne fait pas.

Si xest déjà une variable locale (c'est-à-dire que vous avez une variable var x;ou var x = ...;quelque part plus tôt dans votre portée actuelle (c'est-à-dire la fonction actuelle)) alors elles seront équivalentes. Si ce xn'est pas déjà une variable locale, l'utilisation de la seconde déclarera implicitement une variable globale x. Considérez ce code:

var obj1 = {hey: 10, there: 15};
var obj2 = {heli: 99, copter: 10};
function loop1() {
    for (x in obj1) alert(x);
}
function loop2() {
    for (x in obj2) {
        loop1(); 
        alert(x);
    }
}
loop2();

vous pouvez vous attendre à ce alerte hey, there, heli, hey, there, copter, mais puisque le xest une seule et même il alertera hey, there, there, hey, there, there. Tu ne veux pas ça! Utilisez var xdans vos forboucles.

Pour couronner le tout: si la forboucle est dans la portée globale (c'est-à-dire pas dans une fonction), la portée locale (la portée xest déclarée dans si vous utilisez var x) est la même que la portée globale (la portée xest implicitement déclarée dans si vous utilisez xsans var), les deux versions seront donc identiques.

Claudiu
la source
3
Enfin une réponse complète avec explication et bel exemple. Et cela répond vraiment à la question.
IllidanS4 veut que Monica revienne
22

Vous devriez vraiment déclarer les variables locales avec var, always .

Vous ne devez pas non plus utiliser de boucles "for ... in", sauf si vous êtes absolument sûr que c'est ce que vous voulez faire. Pour parcourir des tableaux réels (ce qui est assez courant), vous devez toujours utiliser une boucle avec un index numérique:

for (var i = 0; i < array.length; ++i) {
  var element = array[i];
  // ...
}

Itérer dans un tableau simple avec "for ... in" peut avoir des conséquences inattendues, car votre boucle peut prendre des attributs du tableau en plus de ceux indexés numériquement.

edit - ici en 2015, il est également bon d'utiliser .forEach()pour itérer dans un tableau:

array.forEach(function(arrayElement, index, array) {
  // first parameter is an element of the array
  // second parameter is the index of the element in the array
  // third parameter is the array itself
  ...
});

La .forEach()méthode est présente sur le prototype Array à partir d'IE9.

Pointu
la source
12

En fait, si vous n'aimez pas la déclaration dans l'en- fortête, vous pouvez faire:

var x;
for (x in set) {
    ...
}

Comme mentionné dans d'autres réponses à cette question, ne pas utiliser vardu tout produit des effets secondaires inutiles comme l'attribution d'une propriété globale.

user422039
la source
9

Utilisez celui avec lequel vous déclarez la variable de boucle var. Les variables déclarées implicitement ont une portée différente qui n'est probablement pas ce que vous vouliez.

Joel Coehoorn
la source
9
for(var i = 0; ...)

est un modèle couramment observé mais différent de

for(int i; ...)

en C ++ en ce que la variable n'est pas étendue au forbloc. En fait, le varest hissé au sommet de la portée (fonction) englobante afin qu'un local isoit effectivement disponible à la fois avant la forboucle (après le début de la portée / fonction actuelle) et après celle-ci.

En d'autres termes, faire:

(function(){ //beginning of your current scope;
 //...
 for(var i in obj) { ... };
})();

est le même que:

(function(){ //beginning of your current scope;
 var i;
 //...
 for(i in obj) { ... };
})();

ES6 a le letmot - clé (au lieu de var) pour limiter la portée au bloc for.

Bien sûr, vous DEVRIEZ utiliser des variables locales (celles déclarées avec varou letou const(dans ES6)) plutôt que des variables globales implicites.

for(i=0; ...)ou for(i in ...)échouera si vous utilisez "use strict";(comme vous devriez) et in'est pas déclaré.

PSkocik
la source
4

Je pense que var est bon pour des raisons de performances.

Javascript ne regardera pas à travers toute la portée globale pour voir si x existe déjà ailleurs.

neebz
la source
3

D'un point de vue général, la première version sera pour un index qui doit vivre dans la portée de la boucle, tandis que l'autre serait n'importe quelle variable dans la portée où le constructeur de la boucle a été appelé.

Si vous allez utiliser l'index de la boucle à l'intérieur de la boucle for et que cela ne sera pas requis par les autres dans les lignes suivantes, mieux vaut déclarer la variable avec "var" pour être sûr que "x" est pour l'index de la boucle initialisé avec 0, tandis que l'autre, si une autre variable "x" est disponible dans ce contexte, elle sera écrasée par l'index de la boucle - c'est que vous aurez des erreurs logiques -.

Matías Fidemraizer
la source