«Var» или без «var» в цикле «for-in» JavaScript?


99

Как правильно написать for-inцикл в JavaScript? Браузер не жалуется ни на один из двух подходов, которые я здесь показываю. Во-первых, есть такой подход, при котором переменная итерации xобъявляется явно:

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

И в качестве альтернативы этот подход, который читается более естественно, но мне не кажется правильным:

for (x in set) {
    ...
}

Просто наткнулся на этот пост при устранении неполадок , почему WebPack генерироваться расслоением файла приводит к возникновению ошибок при для цикла , где varне использовалась , чтобы объявить итератор i: Uncaught ReferenceError: i is not defined. Так что с этого момента я буду использовать его: / webpack странно обрабатывает «глобальные» переменные, подробнее см .: stackoverflow.com/a/40416826
user1063287

Ответы:


103

Использование var, это уменьшает область действия переменной, в противном случае переменная ищет ближайшее замыкание в поисках varоператора. Если он не может найти, varзначит, он глобальный (если вы находитесь в строгом режиме using strict, глобальные переменные вызывают ошибку). Это может привести к следующим проблемам.

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

Если вы напишете var iв цикле for, появится предупреждение 2.

Область видимости и подъема JavaScript


4
Не отвечает на вопрос, это нормально для цикла, а не для
входа

Разве причина i == 5 не связана скорее с подъемом, чем с отсутствием var в цикле for?
Snekse

1
Другой важный аспект в том, что строгий режим запрещает неявное создание глобальных свойств, поэтому использование стандартного цикла for in без оператора var фактически завершится ошибкой и вернет ошибку ReferenceError.
dkugappi

2
Но, исходя из Java, помещение varвнутри forголовы выглядит как локальное в цикле for, а это не так. Следовательно, я предпочитаю стиль user422039 ниже.
njlarsson

2
Что, если у вас есть более одного цикла for в одной области? Вам либо придется повторно использовать индекс (без var), либо вам придется объявить много-много новых переменных (j, k, l, m,…), которые вы больше никогда не будете использовать.
armin

40

Первая версия:

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

объявляет локальную переменную с именем x. Вторая версия:

for (x in set) {
    ...
}

не.

Если xэто уже локальная переменная (т.е. у вас есть var x;или var x = ...;где-то раньше в вашей текущей области (т.е. текущая функция)), они будут эквивалентны. Если xэто еще не локальная переменная, то использование второй неявно объявляет глобальную переменную x. Рассмотрим этот код:

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

Вы могли бы ожидать , что это предупреждение hey, there, heli, hey, there, copter, но так как xэто один и тот же она будет предупреждать hey, there, there, hey, there, there. Вы этого не хотите! Используйте var xв forпетлях.

В довершение ко всему: если forцикл находится в глобальной области видимости (т.е. не в функции), то локальная область видимости (при использовании xобъявляется область видимости var x) такая же, как и глобальная область видимости (область xнеявно объявляется в если вы используете xбез var), поэтому две версии будут идентичны.


3
Наконец, полный ответ с объяснением и хорошим примером. И это действительно отвечает на вопрос.
IllidanS4 хочет вернуть Монику

22

Вы действительно должны объявлять локальные переменные var, всегда .

Вам также не следует использовать циклы for ... in, если вы не уверены, что это именно то, что вы хотите сделать. Для перебора реальных массивов (что довольно часто встречается) всегда следует использовать цикл с числовым индексом:

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

Итерация по простому массиву с помощью «for ... in» может иметь неожиданные последствия, потому что ваш цикл может подбирать атрибуты массива помимо численно проиндексированных.

edit - здесь в 2015 году также можно использовать .forEach()итерацию по массиву:

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() метод присутствует в прототипе Array начиная с IE9 и далее.


12

На самом деле, если вам не нравится объявление в forзаголовке, вы можете сделать:

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

Как упоминалось в других ответах на этот вопрос, неиспользование varвообще вызывает ненужные побочные эффекты, такие как назначение глобального свойства.


9

Используйте тот, в котором вы объявляете переменную цикла с помощью var. Неявно объявленные переменные имеют другую область видимости, которая, вероятно, не соответствует вашим намерениям.


9
for(var i = 0; ...)

это часто встречающийся образец, но он отличается от

for(int i; ...)

в C ++ в том, что переменная не привязана к forблоку. Фактически, varобъект поднимается в верхнюю часть охватывающей области (функции), поэтому локальный объект iбудет эффективно доступен как до forцикла (после начала текущей области / функции), так и после него.

Другими словами, делать:

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

такой же как:

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

ES6 имеет letключевое слово (вместо var) для ограничения области действия блоком for.

Конечно, вам СЛЕДУЕТ использовать локальные переменные (объявленные с помощью varили letилиconst (в ES6)), а не неявные глобальные переменные.

for(i=0; ...)или for(i in ...)потерпит неудачу, если вы используете "use strict";(как следует) и iне заявите.


6

Использование var- самый чистый способ, но оба работают, как описано здесь: https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in

По сути, с помощью varвы гарантируете, что создаете новую переменную. В противном случае вы можете случайно использовать ранее определенную переменную.


4

Я думаю, что var хорош по соображениям производительности.

Javascript не будет просматривать всю глобальную область видимости, чтобы увидеть, существует ли x где-то еще.


3

С общей точки зрения, первая версия будет для индекса, который должен находиться в области видимости цикла, а другой - любой переменной в области видимости, в которой был вызван конструктор цикла.

Если вы собираетесь использовать индекс цикла внутри цикла for и это не потребуется другим в следующих строках, лучше объявить переменную с помощью «var», чтобы вы были уверены, что «x» соответствует индексу цикла, инициализированному с помощью 0, в то время как другой, если в этом контексте доступна другая переменная "x", она будет перезаписана индексом цикла - у вас будут некоторые логические ошибки -.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.