var или нет var в цикле for-in JavaScript?

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

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

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

for (x in set) {
    ...
}

person futlib    schedule 19.04.2011    source источник
comment
Только что наткнулся на этот пост при устранении неполадок, почему сгенерированный файл пакета webpack вызывал ошибки в цикле for, где var не использовался для объявления итератора i: Uncaught ReferenceError: i is not defined. Поэтому я буду использовать его с этого момента:/ webpack странно обрабатывает глобальные переменные, подробнее см.: stackoverflow.com/a/40416826   -  person user1063287    schedule 24.05.2018


Ответы (10)


Используйте 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

person Gabriel Llamas    schedule 19.04.2011
comment
Не отвечает на вопрос, это для обычного цикла for, а не для in. - person IS4; 29.10.2012
comment
Разве причина i==5 не связана больше с подъемом, чем с отсутствием var в цикле for? - person Snekse; 19.04.2013
comment
Другим важным аспектом этого является то, что строгий режим запрещает неявное создание общих свойств, поэтому использование стандартного цикла for in без оператора var фактически завершится ошибкой и вернет ReferenceError. - person dkugappi; 11.06.2013
comment
Но, исходя из Java, размещение var внутри головы for выглядит так, как будто оно локально в цикле for, а это не так. Следовательно, я предпочитаю стиль user422039 ниже. - person njlarsson; 23.10.2014
comment
Что делать, если у вас есть более одного цикла for в одной области видимости? Вам придется либо повторно использовать индекс (без var), либо вам придется объявить много-много новых переменных (j, k, l, m, …), которые вы больше никогда не будете использовать. - person armin; 02.09.2015
comment
@armin, в случае нескольких циклов for я бы объявил var i; перед циклами for, чтобы было понятно, как вы его используете (см. ответ пользователя 422039 ниже: stackoverflow.com/a/5717575/922522). - person Justin; 03.11.2015
comment
@Джастин Имеет смысл. Также имеет смысл, если вы только начали что-то кодировать и не знаете, сколько вложенных циклов вам понадобится. И вы также можете повторно использовать переменную в невложенном цикле. Итак, в конце концов, вы могли бы сказать, что переменная не будет объявлена ​​внутри оператора for, верно? - person armin; 07.11.2015
comment
Это немного вводит в заблуждение, так как объявление var внутри этого цикла for ограничивает область действия i до f, но не ограничивает область действия циклом for. См.: jsbin.com/wopozaxuzo/edit?js,output. - person Assimilater; 08.09.2016

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

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), поэтому две версии будут идентичными.

person Claudiu    schedule 19.04.2011
comment
Наконец полный ответ с объяснением и хорошим примером. И это действительно отвечает на вопрос. - person IS4; 29.10.2012

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

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

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

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

редактировать здесь, в 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.

person Pointy    schedule 19.04.2011
comment
Было бы неплохо сделать использование метода Array .forEach() более ясным в отношении вашего различия между циклом Object for/in и циклом Array for/length. - person Thomas; 26.01.2021

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

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

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

person user422039    schedule 19.04.2011

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

person Joel Coehoorn    schedule 19.04.2011

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 не объявлено.

person PSkocik    schedule 22.05.2015

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

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

person TJHeuvel    schedule 19.04.2011

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

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

person neebz    schedule 19.04.2011

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

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

person Matías Fidemraizer    schedule 19.04.2011

Я всегда использую область видимости блока let, представленную в ES2015.

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

Дополнительная литература и примеры

person user3071284    schedule 06.11.2020