50

考虑以下代码:

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's bad
}

您对此类案件的处理方法是什么?

4

4 回答 4

50

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
}

所以请考虑一下代码的其他读者。不要使用任何可能以错误方式解释的结构。

于 2012-05-29T16:19:22.157 回答
20

let关键字是在 javascript 1.7 中引入的。请在此处找到 MDN 文档

替换varletinsidefor loop解决了这个问题,现在可以在循环范围内声明局部变量。在此处查看 stackoverlow 社区解释:使用“let”和“var”声明变量有什么区别?

未来的代码:

for (let i = 0; i < someVar.length; i++) {
    // do your thing here
}
于 2015-04-28T02:49:56.937 回答
8

我建议将你的循环包含在自执行函数中,这些函数的名称告诉你循环在做什么。这有效地为循环提供了块范围。例如:

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 代码或类似代码。

于 2014-08-20T05:24:49.410 回答
3

我倾向于使用数组内置函数,例如 map、filter 和 forEach,从而完全避免了这个问题。这也会自动为您提供范围循环体,这也非常有用。

如果使用这些与用例不匹配,我通常会求助于 top 声明,这样我就可以避免你提到的问题。

于 2012-05-29T15:09:42.793 回答