„Var” czy brak „var” w pętli „for-in” JavaScript?

99

Jaki jest właściwy sposób pisania for-inpętli w JavaScript? Przeglądarka nie zgłasza reklamacji żadnego z dwóch podejść, które tu pokazuję. Po pierwsze, istnieje takie podejście, w którym zmienna iteracji xjest jawnie zadeklarowana:

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

I alternatywnie to podejście, które brzmi bardziej naturalnie, ale nie wydaje mi się poprawne:

for (x in set) {
    ...
}
futlib
źródło
Właśnie natknąłem to stanowisko podczas rozwiązywania dlaczego WebPack generowana wiązka plik był przyczyną błędów w pętli for, gdzie varnie był używany do deklarowania iterator i: Uncaught ReferenceError: i is not defined. Więc od teraz będę go używać: / webpack dziwnie traktuje zmienne „globalne”, więcej patrz: stackoverflow.com/a/40416826
user1063287

Odpowiedzi:

103

Użyj var, zmniejsza zakres zmiennej, w przeciwnym razie zmienna wyszukuje najbliższe zamknięcie w poszukiwaniu varinstrukcji. Jeśli nie może znaleźć vara, to jest globalne (jeśli jesteś w trybie ścisłym using strict, zmienne globalne generują błąd). Może to prowadzić do problemów, takich jak następujące.

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

Jeśli napiszesz var iw pętli for, pojawi się alert 2.

JavaScript Scoping and Hoisting

Gabriel Llamas
źródło
4
Nie odpowiada na pytanie, to jest normalna pętla for, a nie for in.
IllidanS4 chce, aby Monica wróciła
Czy powodem i == 5 nie jest bardziej podnoszenie niż brak var w pętli for?
Snekse
1
Innym ważnym aspektem jest to, że tryb ścisły zabrania niejawnego tworzenia właściwości gobal, więc użycie standardowej pętli "for in" bez instrukcji var w rzeczywistości zakończy się niepowodzeniem i zwróci błąd ReferenceError.
dkugappi
2
Ale wychodząc z Javy, umieszczenie varwnętrza forgłowy wygląda jak lokalnie w pętli for, ale tak nie jest. Dlatego wolę styl user422039 poniżej.
njlarsson
2
Co się stanie, jeśli zdarzy się, że masz więcej niż jedną pętlę for w jednym zakresie? Będziesz musiał albo ponownie użyć indeksu (bez zmiennej), albo będziesz musiał zadeklarować mnóstwo nowych zmiennych (j, k, l, m,…), których już nigdy nie użyjesz.
armin
40

Pierwsza wersja:

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

deklaruje lokalną zmienną o nazwie x. Druga wersja:

for (x in set) {
    ...
}

nie.

Jeśli xjest już zmienną lokalną (tj. Masz var x;lub var x = ...;gdzieś wcześniej w swoim obecnym zakresie (tj. Bieżącej funkcji)) to będą równoważne. Jeśli xnie jest już zmienną lokalną, użycie drugiej spowoduje niejawne zadeklarowanie zmiennej globalnej x. Rozważ ten kod:

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

można się spodziewać to alert hey, there, heli, hey, there, copter, ale ponieważ xjest jedno i to samo będzie ostrzegać hey, there, there, hey, there, there. Nie chcesz tego! Użyj var xw swoich forpętlach.

Na dodatek: jeśli forpętla znajduje się w zasięgu globalnym (tj. Nie jest w funkcji), wówczas zasięg lokalny (zasięg xjest zadeklarowany w przypadku użycia var x) jest taki sam jak zasięg globalny (zakres xjest niejawnie zadeklarowany w jeśli używasz xbez var), więc obie wersje będą identyczne.

Claudiu
źródło
3
Wreszcie pełna odpowiedź z wyjaśnieniem i ładnym przykładem. I naprawdę odpowiada na pytanie.
IllidanS4 chce, aby Monica wróciła
22

Naprawdę powinieneś zawsze deklarować zmienne lokalne za pomocą var, zawsze .

Nie powinieneś także używać pętli „for ... in”, chyba że masz absolutną pewność, że właśnie tego chcesz. Do iteracji po prawdziwych tablicach (co jest dość powszechne), zawsze powinieneś używać pętli z indeksem numerycznym:

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

Iterowanie po zwykłej tablicy z „for ... in” może mieć nieoczekiwane konsekwencje, ponieważ pętla może pobierać atrybuty tablicy oprócz atrybutów indeksowanych numerycznie.

edytuj - tutaj w 2015 można również użyć .forEach()do iteracji po tablicy:

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

.forEach()Metoda jest obecny na prototypie Array z IE9 przodu.

Spiczasty
źródło
12

Właściwie, jeśli nie lubisz deklaracji w fornagłówku, możesz zrobić:

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

Jak wspomniano w innych odpowiedziach na to pytanie, nieużywanie varw ogóle powoduje niepotrzebne skutki uboczne, takie jak przypisanie właściwości globalnej.

user422039
źródło
9

Użyj tego, w którym deklarujesz zmienną pętli za pomocą var. Zmienne zadeklarowane niejawnie mają inny zakres, który prawdopodobnie nie jest tym, co zamierzałeś.

Joel Coehoorn
źródło
9
for(var i = 0; ...)

to powszechnie spotykany wzór, ale różni się od

for(int i; ...)

w C ++ pod tym względem, że zmienna nie jest objęta zakresem forbloku. W rzeczywistości varzostaje on podniesiony do góry otaczającego zakresu (funkcji), więc lokalna ibędzie efektywnie dostępna zarówno przed forpętlą (po rozpoczęciu bieżącego zakresu / funkcji), jak i po niej.

Innymi słowy, robiąc:

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

jest taki sam jak:

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

ES6 ma letsłowo kluczowe (zamiast var) ograniczające zakres do bloku for.

Oczywiście POWINIENEŚ używać zmiennych lokalnych (zadeklarowanych za pomocą varor letlub lub const(w ES6)) zamiast niejawnych zmiennych globalnych.

for(i=0; ...)lub for(i in ...)zawiedzie, jeśli użyjesz "use strict";(tak jak powinieneś) i inie zostanie zadeklarowany.

PSkocik
źródło
4

Myślę, że var jest dobry ze względu na wydajność.

Javascript nie przejrzy całego zakresu globalnego, aby sprawdzić, czy x już istnieje gdzieś indziej.

neebz
źródło
3

Z ogólnego punktu widzenia, pierwsza wersja będzie dotyczyła indeksu, który musi znajdować się w zakresie pętli, a druga będzie dowolną zmienną w zakresie, w którym został wywołany konstruktor pętli.

Jeśli zamierzasz użyć indeksu pętli wewnątrz pętli for i nie będzie to wymagane przez inne osoby w następnych wierszach, lepiej zadeklaruj zmienną za pomocą „var”, dzięki czemu będziesz mieć pewność, że „x” oznacza indeks pętli zainicjowany wartością 0, podczas gdy druga, jeśli inna zmienna "x" jest dostępna w tym kontekście, zostanie nadpisana przez indeks pętli - to znaczy, że będziesz mieć pewne błędy logiczne -.

Matías Fidemraizer
źródło