Подтвердить что ты не робот

Работа с предупреждением о повторяющемся объявлении для переменных цикла

Рассмотрим следующий код:

for (var i=0; i<100; i++) {
    // your code here
}
// some other code here
for (var i=0; i<500; i++) {
    // custom code here
}

Любой порядочный инструмент lint (jslint, jshint или встроенный IDE) сообщит предупреждение - duplicate declaration of variable i. Это можно решить, используя переменную с другим именем (k, j) или перемещение объявления вверху:

var i; // iterator
for (i=0; i<100; i++) {}
for (i=0; i<500; i++) {}

Я не люблю оба варианта. Обычно я не делаю объявления наверху (и даже если бы я это сделал, мне бы не хотелось видеть вспомогательные переменные - i, j, k) и на самом деле в этих примерах ничего плохого не происходит, чтобы изменить имена переменных.

Хотя мне действительно нужно огромное предупреждение, если я напишу что-то вроде этого:

for (var i=0; i<100; i++) {
    for (var i=0; i<500; i++) {} // now that bad
}

Как вы относитесь к таким случаям?

4b9b3361

Ответ 1

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

Если кто-то, кто не знает JavaScript достаточно хорошо (обычный случай, кстати), видит конструкцию вроде

for (var i=0; i<100; i++) {
    // your code here
}

или видит объявление переменной в блоке

{
    var i;
    //some code
    {
        var j;
        // some code
    }
}

тогда большинство читателей будут думать, что переменные уровня блока будут определены. JavaScript не имеет переменных уровня блока. Все переменные будут интерпретироваться как определенный уровень функции.

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

Кстати, JSLint находит определение переменных внутри блока таким плохим стилем, что прекращает обработку анализа кода. Нет вариантов JSLint, которые могли бы изменить это поведение. Я считаю поведение JSLint не очень хорошим, но я согласен с тем, что объявление переменных внутри цикла for плохо, потому что оно будет считаться большинством людей как код с переменными локального цикла, что неверно.

Если вы используете

for (var i=0; i<100; i++) {
    // your code here
}
// some other code here
for (var i=0; i<500; i++) {
    // custom code here
}

тогда JavaScript перемещает все декларации переменных в начале функции для вас. Таким образом, код будет выглядеть как

var i = undefined, i = undefined; // duplicate declaration which will be reduced
                                  // to one var i = undefined;

for (i=0; i<100; i++) {
    // your code here
}
// some other code here
for (i=0; i<500; i++) {
    // custom code here
}

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

Ответ 2

В javascript 1.7 вводится ключевое слово

let. Пожалуйста, найдите документацию MDN здесь

Замена var на let внутри for loop решает проблему, и теперь можно объявить локальную переменную внутри области цикла. Ознакомьтесь с объяснением сообщества stackoverlow здесь: В чем разница между использованием "let" и "var" объявить переменную?

Код из будущего:

for (let i = 0; i < someVar.length; i++) {
    // do your thing here
}

Ответ 3

Я рекомендую включить ваши петли в функции самоисполнения, имена которых сообщают вам, что делает цикл. Это эффективно обеспечивает область блока для цикла. Например:

var users = response['users']
;(function appendUsers(){
    for (var i = 0; i < users.length; i++) {
        var user      = users[i]
        var userEmail = user['email']
        var userId    = user['id']
        /* etc */ 
    }
})() // appendUsers

Если вы это сделаете:

var i
for (i = 0; i < someVar.length; i++) {
    for (i = 0; i < someOtherVar.length; i++) {
        // This is a bug that a validator will not notice.
    }
}

С другой стороны:

for (var i = 0; i < someVar.length; i++) {
    for (var i = 0; i < someOtherVar.length; i++) {
        // This is a bug that a validator will warn you about.
    }
}
for (var i = 0; i < yetAnotherVar.length; i++) {
    // It will also warn you about this, but so what?
}

Вы можете остановить использование i в качестве итератора:

for (var companyIndex = 0; companyIndex < companies.length; companyIndex++) {
    var company = companies[companyIndex]
}

Если вы все равно используете jQuery, вы можете использовать метод jQuery.each():

$.each(someVar, function(i, value){
    // etc
})

Вы не можете использовать Array.prototype.forEach(), если хотите, чтобы IE8 и ранее работали, если вы не добавили Polyfill код или аналогичный.

Ответ 4

Я использую встроенные функции массива, такие как map, filter и forEach, тем самым избегая проблемы вообще. Это также автоматически дает вам тела петли сферы, что также весьма полезно.

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

Ответ 5

Лучшая практика здесь должна быть хорошим стилем программирования:

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

function myApp() {
    magicLoopAction();
    someOtherMagicStuff();
}
function magicLoopAction() {
    for (var i = 0; i < 42; i++) { 
        // whoopwhoop
    }
}
function someOtherMagicStuff() {
    for (var i = 0; i < 69; i++) { 
        // lint is happy and proud on you
    }
}