63

我只是在使用 JSHint 整理一些 JavaScript 代码。在代码中,我有两个 for 循环都像这样使用:

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

所以两个 for 循环都使用 var i 进行迭代。

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

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

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

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

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

JSLint 顺便说一句。在第一个 for 循环处停止验证,因为我没有在函数顶部定义 var i (这就是我首先切换到 JSHint 的原因)。所以根据这个问题中的例子:我应该使用 JSLint 还是 JSHint JavaScript 验证?– 我应该使用这样的 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++) { ... }

那么是否有最佳实践,或者我可以使用上面的任何代码,这意味着我选择“我的”最佳实践?

4

6 回答 6

60

由于变量声明被提升到它们出现的范围的顶部,解释器将以相同的方式有效地解释两个版本。出于这个原因,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 并认为当您在每个范围的顶部一起声明所有变量时,代码会更清晰。既然这就是代码的解释方式,为什么不编写看起来像它的行为的代码呢?

但是,正如您所观察到的,无论采用何种方法,代码都可以工作,因此它是一种风格/约定的选择,您可以使用您觉得最舒服的任何形式。

于 2013-04-03T09:11:27.803 回答
7

仅在@TSCrowder 的评论中提到:如果您的环境支持它(Firefox,Node.js),在 ES6 中您可以使用let声明

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

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

将范围限制在 for-loop 内。奖励:JSHint 停止抱怨。

于 2016-04-04T07:20:16.113 回答
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.
}
于 2013-04-03T09:12:56.170 回答
4

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

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

let关键字包含在 ECMAScript 6 规范中。

于 2013-04-03T09:12:50.743 回答
4

我知道这个问题已经得到解答,但是如果你想要超级 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增量是预增量(例如 ++idx NOT idx++)。预增量本身比后增量快。

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

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

于 2013-11-19T11:28:22.737 回答
1

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

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

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

我知道声明的变量的范围,var但我在这里讨论代码的可读性。

于 2013-04-03T09:11:11.117 回答