Каков самый идиоматический способ обработки переменных, объявленных в нескольких циклах?

JavaScript имеет только область функций. Таким образом, переменные, объявленные для циклов for, видны для всей функции.

Например,

function foo() {
    for(var i = 0; i < n; i++) {
        // Do something
    }
    // i is still in scope here
}

Когда у нас есть несколько for-loops, это открывает вопрос о том, как мы обрабатываем переменные в этих других циклах.

Используем ли мы другую переменную?

for(var i = 0; i < n; i++) { }
for(var j = 0; j < n; j++) { }

Или мы используем одну и ту же переменную, но просто присваиваем значение (вместо объявления)?

for(var i = 0; i < n; i++) { }
for(i = 0; i < n; i++) { }

Или объявить i вне циклов?

var i;
for(i = 0; i < n; i++) { }
for(i = 0; i < n; i++) { }

Или redeclare i?

for(var i = 0; i < n; i++) { }
for(var i = 0; i < n; i++) { }

Все эти работы (или, по крайней мере, они используются в последних версиях моих браузеров). JSHint не любит последний подход.

Есть ли подход, который является наиболее идиоматическим или иным образом предпочтительным?

Ответ 1

Это действительно зависит от того, для кого вы кодируете. Если вы кодируете компанию или участвуете в библиотеке, вы, конечно, следуете их руководству по стилю. Я видел все это (ожидаем последнего), используемые в библиотеках. Если вам нравится стиль Дугласа Крокфорда, вы пойдете со вторым до последнего и поместите все свои переменные в верхней части области действия (или jslint будет кричать на вас).

Взяв пример из руководства стиля jQuery:

Это считается Хорошим стилем

var i = 0;

if ( condition ) {
    doSomething();
}

while ( !condition ) {
    iterating++;
}

for ( ; i < 100; i++ ) {
    object[ array[ i ] ] = someFn( i );
}

Пока это плохой стиль:

// Bad
if(condition) doSomething();
while(!condition) iterating++;
for(var i=0;i<100;i++) object[array[i]] = someFn(i);

В любом случае, поскольку это стиль, я собираюсь ссылаться на то, как несколько библиотек пишут их для каждого цикла:

Если ваш код будет сведен к минимуму перед его выпуском, это не имеет значения, так как minifiers приведет к какому-либо такому же окончательному представлению в обработке.

Ответ 2

Используя разные переменные, у нас нет проблем.

Повторное использование и переназначение делают код менее читаемым, и если мы удалим объявление позже, мы рискуем присвоить я чему-либо вне области действия.

Объявление я за пределами циклов, у нас нет проблем.

Redeclaring будет проблемой, если ваш инструмент для линта, IDE и т.д. жалуются.

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

Ответ 3

Другое дело, которое отвечает на вопрос по-другому.

Функция с несколькими циклами делает меня подозрительной, потому что:

  • Это может быть слишком много и должно быть разложено в любом случае, и
  • Возможно, лучше написать его более функционально и полностью исключить индекс (он доступен в некоторых функциях each -/map -y)

Ответ 4

Другой подход - использовать функции итератора. Например, в современных браузерах Array будет иметь метод forEach:

var items = ["one", "two", "three"];
var things = ["hello", "goodbye"];

items.forEach(function (item, index) {
   // Do stuff
});

things.forEach(function (item, index) {
   // Do stuff
});

Если вы используете старые браузеры (или пользовательские коллекции), вы можете сделать свой собственный итератор следующим образом:

Array.prototype.forEach = function(callback) {       
   for(var i = 0; i < this.length; i++) {
      callback.apply(this, [this[i], i, this]);
   }
};

Для получения дополнительной информации см. Array.prototype.forEach()

Ответ 5

Любые переменные, объявленные внутри функции, интерпретируются как объявленные в начале функции. Дуг Крокфорд утверждает, что вы должны объявить все свои переменные в первой строке каждой функции.

doSomething = function() {
   var i, ... other variables ...;
   ...
   for (i = 0; i < x; i += 1) {
      ...
   }
   ...
   for (i = 0; i < x; i += 1) {
      ...
   }
}

Таким образом, код читается так же, как он будет обрабатываться механизмом javascript.