开发者问题收集

在 JavaScript 中循环遍历数组

2010-06-10
5414130

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

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

我可以在 JavaScript 中执行相同操作吗?

3个回答

三个主要选项:

  1. for (var i = 0; i < xs.length; i++) { console.log(xs[i]);
  2. xs.forEach((x, i) => console.log(x));
  3. for (const x of xs) { console.log(x);

详细示例如下。


1.顺序 for 循环:

var myStringArray = ["Hello","World"];
var arrayLength = myStringArray.length;
for (var i = 0; i < arrayLength; i++) {
    console.log(myStringArray[i]);
    //Do something
}

优点

  • 适用于所有环境
  • 您可以使用 breakcontinue 流控制语句

缺点

2. Array.prototype.forEach

ES5 规范引入了许多有益的数组方法。其中之一, Array.prototype.forEach ,为我们提供了一种简洁的数组迭代方法:

const array = ["one", "two", "three"]
array.forEach(function (item, index) {
  console.log(item, index);
});

从撰写 ES5 规范发布(2009 年 12 月)到现在已经快十年了,几乎所有现代引擎都在桌面、服务器和移动环境中实现了它,所以使用它们是安全的。

而使用 ES6 箭头函数语法,它就更加简洁了:

array.forEach(item => console.log(item));

除非你计划支持古老的平台(例如, Internet Explorer 11 );您也可以安全使用。

优点

  • 非常简短和简洁。
  • 声明式

缺点

  • 不能使用 break / continue

通常,您可以通过在迭代数组元素之前对其进行过滤来代替 break 命令式循环的需要,例如:

array.filter(item => item.condition < 10)
     .forEach(item => console.log(item))

请记住,如果您正在迭代数组 以从中构建另一个数组 ,则应使用 map 。我已经多次见过这种反模式了。

反模式:

const numbers = [1,2,3,4,5], doubled = [];

numbers.forEach((n, i) => { doubled[i] = n * 2 });

map 的正确用例:

const numbers = [1,2,3,4,5];
const doubled = numbers.map(n => n * 2);

console.log(doubled);

此外,如果您尝试将数组 reduce 为一个值,例如,您想要对数字数组求和,则应使用 reduce 方法。

反模式:

const numbers = [1,2,3,4,5];
const sum = 0;
numbers.forEach(num => { sum += num });

reduce 的正确用法:

const numbers = [1,2,3,4,5];
const sum = numbers.reduce((total, n) => total + n, 0);

console.log(sum);

3. ES6 for-of 语句:

ES6 标准引入了可迭代对象的概念,并定义了一种用于遍历数据的新构造,即 for...of 语句。

此语句适用于任何类型的可迭代对象,也适用于生成器(具有 \[Symbol.iterator\] 属性的任何对象)。

数组对象在 ES6 中定义为内置可迭代对象,因此您可以对其使用此语句:

let colors = ['red', 'green', 'blue'];
for (const color of colors){
    console.log(color);
}

优点

  • 它可以迭代各种各样的对象。
  • 可以使用普通流控制语句( break / continue )。
  • 可用于迭代串行异步值。

缺点

不要使用 for...in

@zipcodeman 建议使用 for...in 语句,但对于迭代数组,应避免使用 for-in ,该语句旨在 枚举 对象属性。

它不应该用于类似数组的对象,因为:

  • 迭代的顺序无法保证;数组索引可能不是按数字顺序访问的。
  • 继承的属性也会被枚举。

第二点是,它会给你带来很多问题,例如,如果你扩展 Array.prototype 对象以在其中包含一个方法,那么该属性也会被枚举。

例如:

Array.prototype.foo = "foo!";
var array = ['a', 'b', 'c'];

for (var i in array) {
    console.log(array[i]);
}

上面的代码将在控制台中记录“a”、“b”、“c”和“foo!”。

如果你使用一些严重依赖本机原型增强的库(例如 MooTools ),那么这可能会成为一个问题。

正如我之前所说, for-in 语句用于 枚举 对象属性,例如例如:

var obj = {
    "a": 1,
    "b": 2,
    "c": 3
};

for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
        // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
        console.log("prop: " + prop + " value: " + obj[prop])
    }
}

在上面的例子中, hasOwnProperty 方法允许您仅枚举 自己的属性 。就是这样,只有对象物理上具有的属性,没有继承的属性。

我建议您阅读以下文章:

Christian C. Salvadó
2010-06-10

是的,假设您的实现包括 for ... of 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 在每次迭代中都不同,但仍可以声明 const 位于循环体内,只要它没有在那里被修改。)

关于稀疏数组的说明:JavaScript 中的数组实际上可能没有存储其 length 所报告的那么多项;该数字只是比存储值的最高索引大一。如果数组包含的元素少于其长度所指示的元素,则称其为 稀疏 。例如,一个数组只在索引 3、12 和 247 处有项是完全合法的;这种数组的 length 是 248,尽管它实际上只存储了 3 个值。如果您尝试访问任何其他索引处的项目,该数组将似乎在那里具有 undefined 值,但该数组与实际存储 undefined 值的数组仍然不同。您可以通过多种方式看到这种差异,例如 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 ]

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

如果您使用 for .. of 迭代数组,则循环主体将执行 length 次,并且对于数组中实际不存在的任何项目,循环控制变量将设置为 undefined 。根据您“执行某项操作”代码的细节,该行为可能正是您想要的,但如果不是,则应使用其他方法。

当然,有些开发人员别无选择,只能使用其他方法,因为无论出于何种原因,他们都针对尚不支持 for ... of 的 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 ...
} );

for ... of 不同, .forEach 仅对数组中实际存在的元素调用该函数。如果传递了包含三个元素且长度为 248 的假设数组,它只会调用该函数三次,而不是 248 次。如果您希望以这种方式处理稀疏数组,那么即使您的解释器支持 for ... of.forEach 也可能是最佳选择。

最后一个选项适用于 所有 版本的 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 ...
}

这种方法的一个优点是您可以选择如何处理稀疏数组。上述代码将运行循环主体完整的 length 次,对于任何缺失元素,将 s 设置为 undefined ,就像 for .. of 一样;如果您只想处理稀疏数组中实际存在的元素,例如 .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 ...
});

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

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

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

Mark Reed
2012-04-16

您可以使用 map ,这是一种功能编程技术“ rel =“ noreferrer”> python 和<a href="http://en.wikipedia.org/wiki/wiki/haskel/haskel_%28programming_language; p> 393465589

一般语法是:

218449697

in General func 在阵列的项目。但是对于JavaScript,它可以采用第二个参数,即项目索引,第三个参数是数组本身。

array.map 的返回值

是另一个数组,因此您可以这样使用:

262183427

,现在x是 [10,20,20,30,40] 。 p>

您不必在线编写功能。它可能是一个单独的功能。

720254862

,其等效等效于:

287871791

除外t获取 new_list

hasen
2010-06-10