在多个for循环中使用相同的变量名是不好的做法吗?

时间:2013-04-03 09:09:33

标签: javascript for-loop jslint jshint

我只是使用JSHint来绘制一些JavaScript代码。在代码中我有两个for循环,它们都是这样使用的:

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

因此两个for循环都使用var i进行迭代。

现在JSHint向我展示了第二个for循环的错误:“'i'已经定义了”。我不能说这不是真的(因为它显然是)但我一直认为这无关紧要因为var i仅用于那个特定的地方。

以这种方式使用for循环是不好的做法吗?我应该在我的代码中为每个for循环使用不同的变量,如

//for-loop 1
for (var i = 0; ...; i++) { ... }

//for-loop 2
for (var j = 0; ...; j++) { ... }

或者这是我可以忽略的错误(因为它不会破坏我的代码,它仍然会做它应该做的事情)?

JSLint btw。停止在第一个for循环验证,因为我没有在函数的顶部定义var i(这就是我首先切换到JSHint的原因)。所以根据这个问题的例子:Should I use JSLint or JSHint JavaScript validation? - 我应该使用像这样的for循环来确认JSLint:

...
var i;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
...
//for-loop 2
for (i = 0; ...; i++) { ... }

这对我来说也很好看,因为这样我应该避免JSLint和JSHint中的错误。但我不确定的是,我是否应该为每个for循环使用不同的变量,如下所示:

...
var i, j;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
//for-loop 2
for (j = 0; ...; j++) { ... }

那么有最好的做法,或者我可以选择上面的任何代码,这意味着我选择“我的”最佳做法?

6 个答案:

答案 0 :(得分:58)

由于变量声明被提升到它们出现的范围的顶部,因此解释器将以相同的方式有效地解释两个版本。出于这个原因,JSHint和JSLint建议将声明移出循环初始化器。

以下代码......

for (var i = 0; i < 10; i++) {}
for (var i = 5; i < 15; i++) {}

...被有效地解释为:

var i;
for (i = 0; i < 10; i++) {}
for (i = 5; i < 15; i++) {}

请注意,实际上只有一个i声明,以及多个赋值 - 你无法真正“重新声明”同一范围内的变量。

要真正回答你的问题...

  

这是最好的做法,还是我可以使用上面的任何代码?

关于如何最好地处理这个问题,有不同的意见。就个人而言,我同意JSLint,并认为当您在每个范围的顶部声明所有变量时代码更清晰。既然这就是解释代码的方式,为什么不编写看起来像它的行为的代码呢?

但是,正如您所观察到的那样,无论采用何种方法,代码都能正常运行,因此它是一种风格/惯例选择,您可以使用您认为最适合的形式。

答案 1 :(得分:6)

javascript中的变量是函数作用域(不是块作用域)。

当你在一个循环中定义var i时,它仍然存在于循环中,也存在于具有该循环的函数中。

见下文,

function myfun() {
    //for-loop 1
    for (var i = 0; ...; i++) { ... }

    // i is already defined, its scope is visible outside of the loop1.
    // so you should do something like this in second loop.

    for (i = 0; ...; j++) { ... }

    // But doing such will be inappropriate, as you will need to remember
    // if `i` has been defined already or not. If not, the `i` would be global variable.
}

答案 2 :(得分:6)

仅在the comment by @TSCrowder中提及:如果您的环境支持它(Firefox,Node.js),在ES6中您可以使用let declaration

//for-loop 1
for (let i = 0; ...; i++) { ... }

//for-loop 2
for (let i = 0; ...; i++) { ... }

将范围限制为for-loop 。奖金:JSHint停止抱怨。

答案 3 :(得分:5)

我知道这个问题已经得到了回答,但是如果你想要超级for循环,那么就这样写:

var names = ['alex','john','paul','nemo'],
    name = '',
    idx = 0,
    len = names.length;

for(;idx<len;++idx)
{
    name = names[idx];
    // do processing...
}

这里发生了一些事情......

  1. 数组长度存储在len中。这会阻止JS在每次迭代时评估names.length

  2. idx增量是PRE-INCREMENT(例如++ idx NOT idx ++)。预增量本身比后增量快。

  3. 存储对name的引用。这是可选的,但如果您将大量使用name变量,则建议使用此选项。每次调用names[idx]都需要在数组中查找索引。无论此搜索是线性搜索,树搜索还是哈希表,查找仍然会发生。因此,将引用存储在另一个变量中以减少查找。

  4. 最后,这只是我个人的偏好,我没有证据或任何性能优势。但是,我总是喜欢将变量初始化为它们将要采用的类型。 name = '',

答案 4 :(得分:4)

JSHint显示错误的原因是因为JS变量范围是函数,变量声明被提升到函数的顶部。

在Firefox中,您可以使用let关键字来定义块范围,但目前其他浏览器不支持。

let关键字包含ECMAScript 6规范。

答案 5 :(得分:1)

最佳做法是减少变量的范围,因此为循环声明迭代变量的最佳方法是

//for-loop 1
for (var i = 0; ...; i++) { ... }

//for-loop 2
for (var j = 0; ...; j++) { ... }

我知道用var声明的变量的范围,但我在这里考虑了代码的可读性。