考虑以下JavaScript:
for (var i = 0; i < foo.length; i++) {
DoStuff(foo[i]);
}
for (var i = 0; i < bar.length; i++) {
DoStuff(bar[i]);
}
对于来自C#背景的开发人员来说,这段代码似乎很好。不幸的是,此代码使用Visual Studio生成警告。
消息1'i'已定义
好的,当然。很明显发生了什么 - 我的第一个声明并没有将我的范围限制在for循环的范围内。我可以做几件事:
for (var i = 0; i < foo.length; i++) {
DoStuff(foo[i]);
}
for (i = 0; i < bar.length; i++) {
DoStuff(bar[i]);
}
我发现这个解决方案不正确,因为第二个for循环现在的'正确性'与第一个循环的正确性相关 - 如果我删除第一个循环,第二个循环必须改变。可替换地:
for (var fooIndex = 0; i < foo.length; i++) {
DoStuff(foo[fooIndex]);
}
for (var barIndex = 0; barIndex < bar.length; barIndex++) {
DoStuff(bar[barIndex]);
}
这似乎更好,而且我目前已经解决了这个问题,但我对这些潜在的长名不满意。我使我的索引的命名标准依赖于它们迭代的变量来保证唯一的名称声明。不幸的是,如果我有一个名为“potentialDiagramImages”的列表,我真的不想这样做:
foreach(var potentialDiagramImagesIndex in potentialDiagramImages){
var foo = potentialDiagramImages[potentialDiagramImagesIndex];
}
这开始在我的眼中“太长的变量名”。不过,我不知道SO是否同意我的意见。此外,如果我必须在同一范围内两次迭代同一个列表(无论出于何种原因),那么这个实现仍然存在初始问题。
无论如何,我只是好奇其他人如何解决这个范围的困境。
答案 0 :(得分:6)
在循环之前(在函数体的顶部)声明i
:
var i;
for (i = 0; i < foo.length; i++) {
DoStuff(foo[i]);
}
for (i = 0; i < bar.length; i++) {
DoStuff(bar[i]);
}
答案 1 :(得分:4)
仅供参考,到目前为止还没有其他人提及它,ECMAscript自第5版以来也为Array.prototype
提供了一些不错的小助手方法。例如
foo.forEach(function( elem ) {
DoStuff( elem );
});
bar.forEach(function( elem ) {
DoStuff( elem );
});
这样可以避免与function level scope
和变量提升混淆。 ES5在所有浏览器中得到广泛支持,您可以(并且可能应该)为旧的浏览器提供一个小的ES5-shim库。
答案 2 :(得分:2)
Javascript没有block level scope所以
for (var i = 0; i < foo.length; i++) {
DoStuff(foo[i]);
}
如果没有函数将其括起来,则创建一个作用于封闭函数或全局的变量。所以最好的方法是在
之外声明索引变量var i;
for (i = 0; i < foo.length; i++) {
DoStuff(foo[i]);
}
for (i = 0; i < bar.length; i++) {
DoStuff(bar[i]);
}
答案 3 :(得分:2)
我特别不关心变量被声明两次。即使声明被提升,我也不喜欢将变量声明远离它所使用的位置。您可以忽略该警告。提升时可能发生的主要错误是,如果你有两个语句声明但不初始化变量,因为新手可能期望第二个声明将变量设置为undefined。
正如其他人所建议的那样,如果你真的想让Visual Studio开心,你只需在你的函数顶部声明你的索引变量,就像jslint想要的那样。
答案 4 :(得分:1)
我通常只是递增我的变量,如果我接下来使用的是j,k,l ......等等。
答案 5 :(得分:0)
JavaScript具有功能范围,并且由于变量提升,var
语句实际上将在包含函数的顶部执行。建议在示波器的顶部放置一个var
语句,并根据需要使用变量:
(function () {
"use strict";
var i,
l;
for (i = 0, l = foo.length; i < l; i++) {
DoStuff(foo[i]);
}
for (i = 0, l = bar.length; i < l; i++) {
DoStuff(bar[i]);
}
}());
答案 6 :(得分:0)
正如在其他答案中已经提到的那样,你可以做的事情并非完全可怕的是在两个循环之外声明索引变量。这会使循环彼此分离(你可以在不引起错误的情况下卸下第一个循环)但是我不喜欢这两件事:它很容易完全删除循环并忘记变量并将变量移动到沉默中“变量用于范围之外”警告。
因此我有两种选择:
使用循环函数代替for循环
array.forEach(function(elem){
doSomething(elem);
});
这还有一个额外的好处,就是不容易出现for-for-for-loops错误。
忽略该警告。
我个人不同意这个特别的警告,并会考虑禁用,如果可能的话。