在Java中,可以使用for循环遍历数组中的对象,如下所示:

String[] myStringArray = {"Hello", "World"};
for (String s : myStringArray) {
    // Do something
}

我可以在JavaScript中做同样的事情吗?


当前回答

在JavaScript中,不建议使用for In循环遍历Array,但最好使用for循环,例如:

for(var i=0, len=myArray.length; i < len; i++){}

它也进行了优化(“缓存”数组长度)。如果你想了解更多,请阅读我关于这个主题的帖子。

其他回答

我认为最好的方法是使用Array.forEach函数。如果你不能使用,我建议从MDN获得polyfill。为了使其可用,在JavaScript中迭代数组当然是最安全的方法。

Array.prototype.forEach()

正如其他人所建议的,这几乎总是你想要的:

var numbers = [1,11,22,33,44,55,66,77,88,99,111];
var sum = 0;
numbers.forEach(function(n){
  sum += n;
});

这样可以确保在处理数组的范围内所需的任何内容都保持在该范围内,并且您只处理数组的值,而不处理对象财产和其他成员,这是为了。。在中。

在大多数情况下,对循环使用常规的C样式。只需记住,循环中的所有内容都与程序的其他部分共享其作用域,{}不会创建新的作用域。

因此:

var sum = 0;
var numbers = [1,11,22,33,44,55,66,77,88,99,111];

for(var i = 0; i<numbers.length; ++i){
  sum += numbers[i];
}

alert(i);

将输出“11”-这可能是或可能不是您想要的。

jsFiddle示例:https://jsfiddle.net/workingClassHacker/pxpv2dh5/7/

是的,假设您的实现包括for。。。在ECMAScript 2015(“Harmony”版本)中引入的功能。。。现在这是一个相当安全的假设。

它的工作原理如下:

// REQUIRES ECMASCRIPT 2015+
var s, myStringArray = ["Hello", "World"];
for (s of myStringArray) {
  // ... do something with s ...
}

或者更好,因为ECMAScript 2015还提供了块范围的变量:

// REQUIRES ECMASCRIPT 2015+
const myStringArray = ["Hello", "World"];
for (const s of myStringArray) {
  // ... do something with s ...
}
// s is no longer defined here

(变量s在每次迭代中都是不同的,但只要不在循环体中修改,它仍然可以在循环体内部声明为常量。)

关于稀疏数组的一个注意事项:JavaScript中的数组实际存储的项目可能不像其长度所报告的那么多;该数字仅比存储值的最高索引大一个。如果数组包含的元素少于其长度所指示的元素,则称为稀疏。例如,只有索引3、12和247处的项的数组是完全合法的;这种数组的长度是248,尽管它实际上只存储3个值。如果您试图访问任何其他索引处的项,则该数组将显示为具有未定义的值,但该数组与实际存储有未定义值的数组不同。您可以从许多方面看到这种差异,例如,在Node REPL显示阵列的方式中:

> a              // array with only one item, at index 12
[ <12 empty items>, 1 ]
> a[0]           // appears to have undefined at index 0
undefined
> a[0]=undefined // but if we put an actual undefined there
undefined
> a              // it now looks like this
[ undefined, <11 empty items>, 1 ]

因此,当您想要“循环遍历”数组时,您需要回答一个问题:是要在其长度所指示的整个范围内循环,并为任何缺失的元素处理未定义的元素,还是只处理实际存在的元素?这两种方法都有大量的应用;这取决于您使用数组的目的。

如果使用for..遍历数组。。中,循环的主体执行长度次,并且对于数组中实际不存在的任何项,循环控制变量设置为undefined。根据“使用”代码的细节,这种行为可能是您想要的,但如果不是,您应该使用不同的方法。

当然,有些开发人员别无选择,只能使用不同的方法,因为无论出于什么原因,他们的目标是一个尚不支持的JavaScript版本。。。属于

只要您的JavaScript实现符合先前版本的ECMAScript规范(例如,它排除了9之前版本的Internet Explorer),那么您就可以使用Array#forEach迭代器方法而不是循环。在这种情况下,您将传递一个函数,对数组中的每个项进行调用:

var myStringArray = [ "Hello", "World" ];
myStringArray.forEach( function(s) { 
     // ... do something with s ...
} );

如果您的实现支持ES6+,当然可以使用箭头函数:

myStringArray.forEach( s => { 
     // ... do something with s ...
} );

不同于。。。of,.forEach只为数组中实际存在的元素调用函数。如果传递了具有三个元素且长度为248的假设数组,它将只调用函数三次,而不是248次。如果这是您想要处理稀疏数组的方式,那么即使您的解释器支持。。。属于

最后一个选项是显式计数循环,适用于所有版本的JavaScript。您只需从0到小于长度的1进行计数,并将计数器用作索引。基本循环如下所示:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  s = myStringArray[i];
  // ... do something with s ...
}

这种方法的一个优点是可以选择如何处理稀疏数组。上面的代码将运行循环体的整个长度,对于任何缺失的元素,s都设置为undefined,就像for。。属于如果您希望只处理稀疏数组中实际存在的元素,例如.forEach,则可以在索引上添加一个简单的in测试:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  if (i in myStringArray) {
    s = myStringArray[i];
    // ... do something with s ...
  }
}

根据实现的优化,将长度值分配给局部变量(而不是在循环条件中包含完整的myStringArray.length表达式)可以显著提高性能,因为它每次都会跳过属性查找。您可以在循环初始化子句中看到长度缓存,如下所示:

var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {

显式计数循环还意味着您可以访问每个值的索引(如果需要的话)。该索引还作为一个额外的参数传递给传递给forEach的函数,因此您也可以这样访问它:

myStringArray.forEach( (s,i) => {
   // ... do something with s and i ...
});

对于of不会为您提供与每个对象关联的索引,但只要您正在迭代的对象实际上是Array的实例(而不是..of的其他可迭代类型之一),您就可以使用Array#entries方法将其更改为[index,item]对的数组,然后对其进行迭代:

for (const [i, s] of myStringArray.entries()) {
  // ... do something with s and i ...
}

用于。。。在其他人提到的语法中,用于循环对象的财产;因为JavaScript中的Array只是一个具有数字属性名称(以及自动更新的长度属性)的对象,理论上可以用它循环Array。但问题是它并不局限于数字属性值(记住,即使是方法实际上也只是值为闭包的财产),也不能保证按数字顺序迭代。因此,对于。。。in语法不应用于循环数组。

在JavaScript中,有很多方法可以循环数组。

下面的代码是流行的代码

/**声明输入*/const items=['你好','世界']/**解决方案1。简单适用于*/console.log(解决方案1。简单用于')for(设i=0;i<items.length;i++){console.log(项[i])}console.log()console.log()/**解决方案2。简单的while*/console.log(解决方案2。简单while')设i=0而(i<items.length){console.log(项[i++])}console.log()console.log()/**解决方案3。对于每个*/console.log(解决方案3。“每个”)items.forEach(item=>{console.log(项)})console.log()console.log()/**解决方案4。的*/console.log(解决方案4。对于')for(常量项,共项){console.log(项)}console.log()console.log()

深奥的

让a=[“你好”,“世界”];while(a.length){console.log(a.shift());}

性能测试

今天(2022-11-13),我在Chrome 107、Safari 15.2和Firefox 106上对选定的解决方案进行了测试。

结论

解决方案C和D在所有阵列的所有浏览器上都是快速或最快的。解决方案A和B在所有阵列的所有浏览器上都是最慢的

后果

细节

我执行3项测试:

small-用于2元素数组(如OP)-可以在此处运行中等-用于10K元素阵列-您可以在这里运行大-对于100K元素数组-您可以在这里运行

下面的代码段显示了测试中使用的代码。

函数A(A){设r=0;而(a.length)r+=a.shift().length;返回r;}函数B(a){设r=0;对于(i in a)r+=a[i]长度;返回r;}函数C(a){设r=0;对于(a的x)r+=x.length;返回r;}函数D(a){设r=0;对于(i=0;i<a.length;++i)r+=a[i].length;返回r;}函数E(a){设r=0;a.对于每个(x=>r+=x.length);返回r;}let arr=[“你好”,“世界!”];[A,B,C,D,E].forEach(f=>console.log(`${f.name}:${f([…arr])}`))

以下是Chrome对于中等阵列的示例结果:

var array=['hai','hello','how','are','you']$(文档).ready(函数(){$('#clickButton').click(函数(){对于(var i=0;i<array.length;i++){警报(阵列[i])}})})<script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js“></script><input id=“clickButton”value=“click Me”type=“button”/><div id=“show”></div>