“Var” ou não “var” no loop “for-in” do JavaScript?

99

Qual é a maneira correta de escrever um for-inloop em JavaScript? O navegador não emite uma reclamação sobre nenhuma das duas abordagens que mostro aqui. Primeiro, há esta abordagem em que a variável de iteração xé declarada explicitamente:

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

E, alternativamente, essa abordagem que parece mais natural, mas não parece correta para mim:

for (x in set) {
    ...
}
futlib
fonte
Apenas me deparei com este post, quando a resolução de problemas por que um Webpack gerado arquivo de pacote estava causando erros em um loop onde varnão foi utilizado para declarar o iterador i: Uncaught ReferenceError: i is not defined. Portanto, irei usá-lo de agora em diante: / webpack trata variáveis ​​"globais" de maneira estranha, para obter mais informações, consulte: stackoverflow.com/a/40416826
user1063287

Respostas:

103

Use var, reduz o escopo da variável, caso contrário, a variável procura o fechamento mais próximo em busca de uma varinstrução. Se ele não puder encontrar um, varentão ele é global (se você estiver em um modo estrito using strict, as variáveis ​​globais geram um erro). Isso pode levar a problemas como os seguintes.

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

Se você escrever var ino loop for, o alerta será exibido 2.

Escopo e elevação de JavaScript

Gabriel Llamas
fonte
4
Não responde à pergunta, isso é normal para loop, não para in.
IllidanS4 quer Monica de volta 29/10/12
A razão i == 5 não é mais devido ao içamento do que à falta de var no loop for?
Snekse
1
Outro aspecto importante para isso é que o modo estrito proíbe a criação implícita de propriedades gobal, portanto, usar o loop padrão "for in" sem a instrução var na verdade falhará e retornará um ReferenceError.
dkugappi
2
Mas, vindo de Java, colocar o vardentro da forcabeça parece que é local no loop for, o que não é. Portanto, prefiro o estilo do user422039 abaixo.
njlarsson
2
E se você tiver mais de um loop for em um escopo? Você terá que reutilizar o índice (sem var) ou declarar muitas e muitas variáveis ​​novas (j, k, l, m, ...) que nunca mais usará.
armin
40

A primeira versão:

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

declara uma variável local chamada x. A segunda versão:

for (x in set) {
    ...
}

não.

Se xjá for uma variável local (ou seja, você tem um var x;ou em var x = ...;algum lugar anterior em seu escopo atual (ou seja, a função atual)) então eles serão equivalentes. Se xainda não for uma variável local, o uso da segunda irá declarar implicitamente uma variável global x. Considere este código:

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();

você pode esperar que isso alerta hey, there, heli, hey, there, copter, mas desde que o xé uma ea mesma coisa vai alertar hey, there, there, hey,there , there. Você não quer isso! Use var xem seus forloops.

Para completar: se o forloop estiver no escopo global (ou seja, não em uma função), então o escopo local (o escopo xé declarado em se você usar var x) é o mesmo que o escopo global (o escopo xé declarado implicitamente em se você usar xsem var), então as duas versões serão idênticas.

Claudiu
fonte
3
Finalmente uma resposta completa com explicação e bom exemplo. E realmente responde à pergunta.
IllidanS4 quer Monica de volta em
22

Você realmente deve declarar variáveis ​​locais com var, sempre .

Você também não deve usar loops "for ... in", a menos que tenha absoluta certeza de que é isso o que deseja fazer. Para iterar por meio de matrizes reais (o que é bastante comum), você deve sempre usar um loop com um índice numérico:

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

Iterar através de um array simples com "for ... in" pode ter consequências inesperadas, porque seu loop pode pegar atributos do array além dos indexados numericamente.

editar - aqui em 2015 também é bom usar .forEach()para iterar por meio de uma matriz:

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
  ...
});

O .forEach()método está presente no protótipo do Array do IE9 em diante.

Pontudo
fonte
12

Na verdade, se você não gosta de declarações no forcabeçalho, pode fazer:

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

Conforme mencionado em outras respostas a esta pergunta, não usar varproduz efeitos colaterais desnecessários, como atribuir uma propriedade global.

user422039
fonte
9

Use aquele em que você declara a variável de loop com var. Variáveis ​​declaradas implicitamente têm um escopo diferente que provavelmente não é o que você pretendia.

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

é um padrão comumente visto, mas é diferente de

for(int i; ...)

em C ++ em que a variável não tem como escopo o forbloco. Na verdade, o varé içado para o topo do escopo delimitador (função) para que um local iesteja efetivamente disponível antes do forloop (após o início do escopo / função atual) e depois dele.

Em outras palavras, fazer:

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

é o mesmo que:

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

ES6 tem a letpalavra - chave (em vez de var) para limitar o escopo ao bloco for.

Claro, você DEVE usar variáveis ​​locais (aquelas declaradas com varou letou const(em ES6)) ao invés de globais implícitas.

for(i=0; ...)ou for(i in ...)falhará se você usar "use strict";(como deveria) e inão for declarado.

PSkocik
fonte
4

Acho que var é bom por motivos de desempenho.

Javascript não examinará todo o escopo global para ver se x já existe em algum outro lugar.

Neebz
fonte
3

De um ponto de vista geral, a primeira versão será para um índice que deve residir no escopo do loop, enquanto a outra seria qualquer variável no escopo onde o construtor do loop foi invocado.

Se você for usar o índice do loop dentro do loop for e isso não será exigido por outros nas próximas linhas, é melhor declarar a variável com "var" para ter certeza de que "x" é o índice do loop for inicializado com 0, enquanto a outra, se outra variável "x" estiver disponível neste contexto, ela será sobrescrita pelo índice do loop - que você terá alguns erros lógicos -.

Matías Fidemraizer
fonte