在JavaScript中循环遍历数组

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

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

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

5050258 次浏览

三个主要选项:

  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规范介绍了许多有益的数组方法。其中之一,#0,为我们提供了一种迭代数组的简洁方法:

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);

此外,如果您尝试将数组减少化为一个值,例如,您想对一个数字数组求和,您应该使用减少方法。

反模式:

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

正确使用duce

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

3. ES6for-of语句:

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

此语句适用于任何类型的可迭代对象以及生成器(任何具有#0属性的对象)。

根据定义,数组对象是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方法只允许枚举自己的财产。就是这样,只有对象物理上拥有的属性,没有继承的属性。

我建议你阅读以下文章:

您可以使用map,这是一种函数式编程技术,也可以在pythonhaskell等其他语言中使用。

[1,2,3,4].map( function(item) {alert(item);})

一般语法是:

array.map(func)

一般来说,func会接受一个参数,这是数组的一个项目。但在JavaScript的情况下,它可以接受第二个参数,这是项目的索引,第三个参数是数组本身。

array.map的返回值是另一个数组,所以你可以这样使用它:

var x = [1,2,3,4].map( function(item) {return item * 10;});

现在x是[10,20,30,40]

您不必内联编写函数。它可以是一个单独的函数。

var item_processor = function(item) {// Do something complicated to an item}
new_list = my_list.map(item_processor);

这相当于:

 for (item in my_list) {item_processor(item);}

除非你没有得到new_list

Opera,Safari,Firefox和Chrome现在都共享一组增强的数组方法来优化许多常见的循环。

您可能不需要所有这些,但它们可能非常有用,或者如果每个浏览器都支持它们的话。

Mozilla Labs发布了他们和webkit都使用的算法,以便您可以自己添加它们。

过滤器返回满足某些条件或测试的项数组。

如果每个数组成员都通过测试,则返回true。

如果通过测试,则返回true。

for每个在每个数组成员上运行一个函数,不返回任何内容。

地图类似于for每个,但它返回每个元素的操作结果的数组。

这些方法都将一个函数作为其第一个参数,并有一个可选的第二个参数,这是一个对象,您希望在数组成员循环函数时将其范围强加给它们。

忽略它,直到你需要它。

indexOflastIndexOf标签类型找到与其参数完全匹配的第一个或最后一个元素的适当位置。

(function(){var p, ap= Array.prototype, p2={filter: function(fun, scope){var L= this.length, A= [], i= 0, val;if(typeof fun== 'function'){while(i< L){if(i in this){val= this[i];if(fun.call(scope, val, i, this)){A[A.length]= val;}}++i;}}return A;},every: function(fun, scope){var L= this.length, i= 0;if(typeof fun== 'function'){while(i<L){if(i in this && !fun.call(scope, this[i], i, this))return false;++i;}return true;}return null;},forEach: function(fun, scope){var L= this.length, i= 0;if(typeof fun== 'function'){while(i< L){if(i in this){fun.call(scope, this[i], i, this);}++i;}}return this;},indexOf: function(what, i){i= i || 0;var L= this.length;while(i< L){if(this[i]=== what)return i;++i;}return -1;},lastIndexOf: function(what, i){var L= this.length;i= i || L-1;if(isNaN(i) || i>= L)i= L-1;elseif(i< 0) i += L;while(i> -1){if(this[i]=== what)return i;--i;}return -1;},map: function(fun, scope){var L= this.length, A= Array(this.length), i= 0, val;if(typeof fun== 'function'){while(i< L){if(i in this){A[i]= fun.call(scope, this[i], i, this);}++i;}return A;}},some: function(fun, scope){var i= 0, L= this.length;if(typeof fun== 'function'){while(i<L){if(i in this && fun.call(scope, this[i], i, this))return true;++i;}return false;}}}for(p in p2){if(!ap[p])ap[p]= p2[p];}return true;})();

在JavaScript中,不建议使用for-in循环遍历数组,但最好使用for循环,例如:

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

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

有一种方法可以做到这一点,在循环中只有很少的隐式作用域,并取消额外的变量。

var i = 0,item;
// Note this is weak to sparse arrays or falsey valuesfor ( ; item = myStringArray[i++] ; ){item; // This is the string at the index.}

或者如果你真的想得到id并有一个非常经典的for循环:

var i = 0,len = myStringArray.length; // Cache the length
for ( ; i < len ; i++ ){myStringArray[i]; // Don't use this if you plan on changing the length of the array}

现代浏览器都支持迭代器方法forEachmapreducefilter以及阵列原型上的许多其他方法。

使用循环…

var i = 0, item, items = ['one', 'two', 'three'];while(item = items[i++]){console.log(item);}

它记录:“一”,“二”和“三”

对于相反的顺序,一个更有效的循环:

var items = ['one', 'two', 'three'], i = items.length;while(i--){console.log(items[i]);}

它记录:“三”,“二”和“一”

或者经典的for循环:

var items = ['one', 'two', 'three']for(var i=0, l = items.length; i < l; i++){console.log(items[i]);}

它记录:“一”,“二”,“三”

参考:谷歌闭包:如何不写JavaScript

有一个方法只迭代自己的对象属性,不包括原型的属性:

for (var i in array) if (array.hasOwnProperty(i)) {// Do something with array[i]}

但它仍然会迭代自定义属性。

在JavaScript中,任何自定义属性都可以分配给任何对象,包括数组。

如果想要迭代稀疏数组,应该使用for (var i = 0; i < array.length; i++) if (i in array)array.forEaches5shim

是的,假设您的实现包括ECMAScript 2015(“Harmony”版本)中引入的#0…#1功能……这是一个非常安全的假设。

它是这样工作的:

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

> a[ <12 empty items>, 1 ]> a[0]undefined> a[0]=undefinedundefined> a[ undefined, <11 empty items>, 1 ]

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

如果你用forof遍历一个数组,循环的主体会执行length次,对于数组中实际不存在的任何项,循环控制变量会设置为undefined。根据你的“做点什么”代码的细节,这种行为可能是你想要的,但如果不是,你应该使用不同的方法。

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

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

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

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

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

forof不同,.forEach只调用数组中实际存在的元素的函数。如果传递我们假设的数组,其中有三个元素,长度为248,它只会调用该函数三次,而不是248次。如果这就是你想要处理稀疏数组的方式,即使你的解释器支持forof.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,就像forof;如果你只想处理稀疏数组的实际存在的元素,就像.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 ...});

forof不会给你与每个对象关联的索引,但只要你迭代的对象实际上是Array的实例(而不是其他可迭代类型forof之一),你可以使用数组#条目方法将其更改为[index, Item]对的数组,然后迭代:

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

其他人提到的forin语法是用于循环遍历对象的属性;由于JavaScript中的Array只是一个具有数字属性名称(和自动更新的length属性)的对象,理论上你可以用它循环遍历Array。但问题是它并没有将自己限制在数字属性值上(请记住,即使是方法实际上也只是其值是闭包的属性),也不能保证会循环遍历数字顺序的属性。因此,forin语法应该没有用于循环遍历Array。

我强烈建议使用Underscore.js库。它为您提供了各种函数,您可以使用这些函数来迭代数组/集合。

例如:

_.each([1, 2, 3], function(num){ alert(num); });=> alerts each number in turn...

这不是100%相同,但很相似:

   var myStringArray = ['Hello', 'World']; // The array uses [] not {}for (var i in myStringArray) {console.log(i + ' -> ' + myStringArray[i]); // i is the index/key, not the item}

如果你想要一个简洁的方法来写一个快速循环,你可以反向迭代:

for (var i=myArray.length;i--;){var item=myArray[i];}

这样做的好处是缓存长度(类似于for (var i=0, len=myArray.length; i<len; ++i),不同于for (var i=0; i<myArray.length; ++i)),同时键入的字符更少。

甚至有些时候您应该反向迭代,例如在迭代直播节点列表时,您计划在迭代期间从DOM中删除项目。

如果您使用的是jQuery库,请考虑使用http://api.jquery.com/jQuery.each/

从留档:

#0

退货:对象

问题描述一个泛型迭代器函数,可用于无缝地遍历对象和数组。数组和类数组具有长度属性的对象(例如函数的参数对象)由数字索引迭代,从0到长度-1。其他对象是通过它们的命名属性迭代。

$.each()函数与$(selector).each()不同,它是用于专门迭代jQuery对象。$.each()函数可用于迭代任何集合,无论它是map(JavaScript对象)或数组。在数组的情况下,回调传递一个数组索引和一个相应的数组值时间。(该值也可以通过this关键字访问,但是Javascript将始终将this值包装为Object,即使它是一个简单的字符串或数字值。)该方法返回其第一个参数,迭代的对象。

我还没有看到这种变化,我个人最喜欢:

给定一个数组:

var someArray = ["some", "example", "array"];

你可以遍历它,而不必访问长度属性:

for (var i=0, item; item=someArray[i]; i++) {// item is "some", then "example", then "array"// i is the index of item in the arrayalert("someArray[" + i + "]: " + item);}

看这个JsFiddle演示:http://jsfiddle.net/prvzk/

这仅适用于没有稀疏的数组。这意味着数组中的每个索引处实际上都有一个值。然而,我发现实际上我很少在JavaScript中使用稀疏数组…在这种情况下,将对象用作map/hashtable通常要容易得多。如果你确实有一个稀疏数组,并且想要循环超过0…长-1,你需要for(var i=0; iif来检查当前索引处的元素是否实际定义。

此外,正如CMS在下面的评论中提到的,你只能在不包含任何假值的数组上使用它。示例中的字符串数组可以工作,但是如果你有空字符串,或者数字是0或NaN等,循环将过早中断。在实践中,这对我来说几乎不是问题,但这是需要记住的事情,这使得这是一个在使用它之前需要考虑的循环…这可能会使某些人失去它的资格:)

我喜欢这个循环的原因是:

  • 写起来很短
  • 不需要访问(更不用说缓存)长度属性
  • 要访问的项目在循环中自动定义你选的名字下的身体。
  • 与array.push和array.splice非常自然地结合使用数组,如列表/堆栈

这样做的原因是数组规范要求当您从索引>=数组长度中读取项目时,它将返回未定义。当您写入这样的位置时,它实际上会更新长度。

对我来说,这个结构最接近于我喜欢的Java5语法:

for (String item : someArray) {}

…还有一个额外的好处,那就是知道循环中的当前索引

var x = [4, 5, 6];for (i = 0, j = x[i]; i < x.length; j = x[++i]) {console.log(i,j);}

干净多了…

(const s of myStringArray){//获取自定义字符串

(直接回答你的问题:现在你可以!)

大多数其他答案是正确的,但他们没有提到(在撰写本文时)ECMAScript<的罢工>62015带来了一种新的迭代机制,#0循环。

这种新语法是在JavaScript中迭代数组的最优雅的方式(只要你不需要迭代索引)。

它目前适用于Firefox 13+,Chrome37+,并且它本身不适用于其他浏览器(请参阅下面的浏览器兼容性)。幸运的是,我们有JavaScript编译器(例如巴别塔),允许我们今天使用下一代功能。

它也适用于Node.js(我在0.12.0版上测试过)。

迭代数组

// You could also use "let" or "const" instead of "var" for block scope.for (var letter of ["a", "b", "c"]) {console.log(letter);}

迭代对象数组

const band = [{firstName : 'John', lastName: 'Lennon'},{firstName : 'Paul', lastName: 'McCartney'}];
for(const member of band){console.log(member.firstName + ' ' + member.lastName);}

迭代生成器:

(示例摘自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)

function* fibonacci() { // A generator functionlet [prev, curr] = [1, 1];while (true) {[prev, curr] = [curr, prev + curr];yield curr;}}
for (const n of fibonacci()) {console.log(n);// Truncate the sequence at 1000if (n >= 1000) {break;}}

兼容性表:http://kangax.github.io/compat-table/es6/#test-for..of_loops

规格说明:http://wiki.ecmascript.org/doku.php?id=harmony:迭代器

}

优化的方法是缓存数组的长度并使用单个变量模式,使用单个var关键字初始化所有变量。

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

如果迭代顺序无关紧要,那么你应该尝试反向循环。它是最快的,因为它减少了开销条件测试,并且递减在一条语句中:

var i,myStringArray = ["item1","item2"];for (i =  myStringArray.length; i--) {alert(myStringArray[i]);}

或者使用循环更好更干净:

var myStringArray = ["item1","item2"],i = myStringArray.length;while(i--) {// Do something with fruits[i]}

最优雅快捷的方式

var arr = [1, 2, 3, 1023, 1024];for (var value; value = arr.pop();) {value + 1}

http://jsperf.com/native-loop-performance/8


编辑(因为我错了)


比较循环遍历100000项数组的方法,并每次使用新值执行最小操作。

准备:

<script src="//code.jquery.com/jquery-2.1.0.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script><script>Benchmark.prototype.setup = function() {// Fake function with minimal action on the valuevar tmp = 0;var process = function(value) {tmp = value; // Hold a reference to the variable (prevent engine optimisation?)};        
// Declare the test Arrayvar arr = [];for (var i = 0; i < 100000; i++)arr[i] = i;};</script>

测试:

<a href="http://jsperf.com/native-loop-performance/16"title="http://jsperf.com/native-loop-performance/16"><img src="http://i.imgur.com/YTrO68E.png" title="Hosted by imgur.com" /></a>

那么,这个怎么样:

for (var key in myStringArray) {console.log(myStringArray[key]);}

在JavaScript中循环数组有多种方法。

泛型循环:

var i;for (i = 0; i < substr.length; ++i) {// Do something with `substr[i]`}

ES5为每个人:

substr.forEach(function(item) {// Do something with `item`});

jQuery.each:

jQuery.each(substr, function(index, item) {// Do something with `item` (or `this` is also `item` if you like)});

查看这个以获取详细信息,或者您也可以检查MDN以通过JavaScript中的数组进行循环&使用jQuery检查每个jQuery

例如,我在Firefox控制台中使用:

[].forEach.call(document.getElementsByTagName('pre'), function(e){console.log(e);})

您可以使用querySelectorAll来获得相同的结果

document.querySelectorAll('pre').forEach( (e) => {console.log(e.textContent);})
<pre>text 1</pre><pre>text 2</pre><pre>text 3</pre>

当然,这是低效的,许多人鄙视它,但它是最接近提到的:

var myStringArray = ["Hello","World"];myStringArray.forEach(function(f){// Do something})

导言

自从我上大学以来,我已经用Java,JavaScript,Pascal,ABAP,PHP,进度4GL,C/C++以及其他一些我现在想不出的语言进行编程。

虽然它们都有自己的语言特性,但每种语言都有许多相同的基本概念。这些概念包括过程/函数、IF语句、FOR循环和WHILE循环。


传统的for循环

传统的for循环有三个组成部分:

  1. 初始化:在第一次执行look块之前执行
  2. 条件:每次在执行循环块之前检查一个条件,如果为false,则退出循环
  3. 事后的想法:每次执行循环块后执行

这三个组件由;符号相互分隔。这三个组件中每个组件的内容都是可选的,这意味着以下是尽可能最小的for循环:

for (;;) {// Do stuff}

当然,您需要在for循环中的某个地方包含if(condition === true) { break; }if(condition === true) { return; }以使其停止运行。

但是,通常情况下,初始化用于声明索引,条件用于将该索引与最小值或最大值进行比较,事后的想法用于增加索引:

for (var i = 0, length = 10; i < length; i++) {console.log(i);}

使用传统的for循环遍历数组

遍历数组的传统方法是这样的:

for (var i = 0, length = myArray.length; i < length; i++) {console.log(myArray[i]);}

或者,如果你喜欢向后循环,你这样做:

for (var i = myArray.length - 1; i > -1; i--) {console.log(myArray[i]);}

然而,有许多可能的变体,例如这个:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {console.log(value);}

…或者这个…

var i = 0, length = myArray.length;for (; i < length;) {console.log(myArray[i]);i++;}

…或者这个:

var key = 0, value;for (; value = myArray[key++];){console.log(value);}

哪一个效果最好,很大程度上取决于个人品味和你正在实现的具体用例。

请注意,所有浏览器都支持这些变体,包括非常非常旧的浏览器!


while循环

for循环的一种替代方法是while循环。要循环遍历数组,您可以这样做:

var key = 0;while(value = myArray[key++]){console.log(value);}

与传统的for循环一样,即使是最古老的浏览器也支持while循环。

此外,请注意,每个这时候循环都可以重写为for循环。例如,上面的while循环的行为与这个for-loop完全相同:

for(var key = 0; value = myArray[key++];){console.log(value);}

For...infor...of

在JavaScript中,你也可以这样做:

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

但是,应该小心使用,因为它的行为在所有情况下都与传统的for循环不同,并且需要考虑潜在的副作用。有关更多详细信息,请参阅为什么在数组迭代中使用"for… in"是个坏主意?

作为#0的替代方案,现在也有#1。以下示例显示了for...of循环和for...in循环之间的区别:

var myArray = [3, 5, 7];myArray.foo = "hello";
for (var i in myArray) {console.log(i); // logs 0, 1, 2, "foo"}
for (var i of myArray) {console.log(i); // logs 3, 5, 7}

此外,您需要考虑没有Internet Explorer版本支持for...of边缘12+支持),并且for...in至少需要Internet Explorer 10。


Array.prototype.forEach()

for-loops的替代方法是#1,它使用以下语法:

myArray.forEach(function(value, key, myArray) {console.log(value);});

所有现代浏览器以及Internet Explorer 9及更高版本都支持Array.prototype.forEach()


图书馆

最后,许多实用程序库也有自己的foreach变体。AFAIK,三个最流行的是这些:

#0,在jQuery

$.each(myArray, function(key, value) {console.log(value);});

#0,在<强>Underscore.js

_.each(myArray, function(value, key, myArray) {console.log(value);});

#0,在洛破折号

_.forEach(myArray, function(value, key) {console.log(value);});

简短的回答:是的。你可以这样做:

var myArray = ["element1", "element2", "element3", "element4"];
for (i = 0; i < myArray.length; i++) {console.log(myArray[i]);}

在浏览器控制台中,您可以看到打印的“element1”、“element2”等内容。

如果你想使用jQuery,它的留档中有一个很好的例子:

 $.each([ 52, 97 ], function( index, value ) {alert( index + ": " + value );});

最好使用顺序for循环:

for (var i = 0; i < myStringArray.length; i++) {// Do something}

在JavaScript中有几种方法可以做到这一点。前两个示例是JavaScript示例。第三个使用JavaScript库,即jQuery使用.each()函数。

var myStringArray = ["hello", "World"];for(var i in myStringArray) {alert(myStringArray[i]);}

var myStringArray = ["hello", "World"];for (var i=0; i < myStringArray.length; i++) {alert(myStringArray[i]);}

var myStringArray = ["hello", "World"];$.each(myStringArray, function(index, value){alert(value);})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

var myStringArray = ["hello", "World"];myStringArray.forEach(function(val, index){console.log(val, index);})
var obj = ["one","two","three"];
for(x in obj){console.log(obj[x]);}

数组循环:

for(var i = 0; i < things.length; i++){var thing = things[i];console.log(thing);}

对象循环:

for(var prop in obj){var propValue = obj[prop];console.log(propValue);}

在JavaScript中,有很多解决方案可以循环数组。

下面的代码是流行的

/** Declare inputs */const items = ['Hello', 'World']
/** Solution 1. Simple for */console.log('solution 1. simple for')
for (let i = 0; i < items.length; i++) {console.log(items[i])}
console.log()console.log()
/** Solution 2. Simple while */console.log('solution 2. simple while')
let i = 0while (i < items.length) {console.log(items[i++])}
console.log()console.log()
/** Solution 3. forEach*/console.log('solution 3. forEach')
items.forEach(item => {console.log(item)})
console.log()console.log()
/** Solution 4. for-of*/console.log('solution 4. for-of')
for (const item of items) {console.log(item)}
console.log()console.log()

在我看来,最好的方法是使用Array.for每个函数。如果你不能使用它,我建议从MDN获取Poly填充。为了使它可用,这当然是在JavaScript中迭代数组的最安全方法。

Array.prototype.for每个()

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

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

这确保了在处理数组的范围内需要的任何东西都保持在该范围内,并且您只处理数组的值,而不是对象属性和其他成员,这就是for .. in所做的。

在大多数情况下,使用常规的C风格for循环是有效的。重要的是要记住循环中的所有内容都与程序的其余部分共享其范围,{}不会创建新的范围。

因此:

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/

,您可以在JavaScript中使用循环执行相同的操作,但不限于。在JavaScript中有很多方法可以对数组进行循环。假设您在下面有这个数组,并且您想对其进行循环:

var arr = [1, 2, 3, 4, 5];

这些是解决方案:

1)for循环

for循环是JavaScript中循环数组的常见方式,但它不被认为是大型数组的最快解决方案:

for (var i=0, l=arr.length; i<l; i++) {console.log(arr[i]);}

(2)循环

年间循环被认为是遍历长数组的最快方式,但它在JavaScript代码中通常使用较少:

let i=0;
while (arr.length>i) {console.log(arr[i]);i++;}

3)边做边做
do whilewhile做了同样的事情,有一些语法差异如下:

let i=0;do {console.log(arr[i]);i++;}while (arr.length>i);

这些是执行JavaScript循环的主要方法,但还有更多方法可以做到这一点。

我们还使用for in循环来循环JavaScript中的对象。

还要看看JavaScript中数组上的map()filter()reduce()等函数。它们可能比使用whilefor更快更好。

如果您想了解有关JavaScript中数组上的异步函数的更多信息,这是一篇很好的文章。

函数式编程已经在有充分的理由:功能技术可以帮助您编写更容易编写的声明性代码一目了然,重构和测试。

函数式编程的基石之一是它的特殊用途列表和列表操作。而这些东西正是听起来像是:事物的数组,以及你对它们所做的事情。但功能性思维模式对他们的态度与你有所不同可以期待

这篇文章将仔细看看我喜欢称之为“大三个“列表操作:map、filter和duce。包装你的头围绕这三个功能是朝着能够编写干净的功能代码,并打开了巨大的大门功能强大的函数式和反应式编程技术。

这也意味着你再也不用写for循环了。

阅读更多>>这里

似乎所有的变体都被列出了,除了forEach豆沙

_.forEach([1, 2], (value) => {console.log(value);});

一个简单的单行解决方案:

arr = ["table", "chair"];
// Solutionarr.map((e) => {console.log(e);return e;});

在JavaScript中循环遍历函数式编程方式中的数组的一些用例:

1.只需循环遍历数组

const myArray = [{x:100}, {x:200}, {x:300}];
myArray.forEach((element, index, array) => {console.log(element.x); // 100, 200, 300console.log(index); // 0, 1, 2console.log(array); // same myArray object 3 times});

注意:Array.prototype.for严格来说,每个()不是一个函数,因为它作为输入参数的函数不应该返回一个值,因此不能被视为一个纯函数。

2.检查数组中的任何元素是否通过测试

const people = [{name: 'John', age: 23},{name: 'Andrew', age: 3},{name: 'Peter', age: 8},{name: 'Hanna', age: 14},{name: 'Adam', age: 37}];
const anyAdult = people.some(person => person.age >= 18);console.log(anyAdult); // true

3.转换到新数组

const myArray = [{x:100}, {x:200}, {x:300}];
const newArray= myArray.map(element => element.x);console.log(newArray); // [100, 200, 300]

注意:map()方法创建一个新数组,其结果是对调用数组中的每个元素调用提供的函数。

4.总结一个特定的属性,并计算其平均值

const myArray = [{x:100}, {x:200}, {x:300}];
const sum = myArray.map(element => element.x).reduce((a, b) => a + b, 0);console.log(sum); // 600 = 0 + 100 + 200 + 300
const average = sum / myArray.length;console.log(average); // 200

5.基于原始数组创建一个新数组,但不修改它

const myArray = [{x:100}, {x:200}, {x:300}];
const newArray= myArray.map(element => {return {...element,x: element.x * 2};});
console.log(myArray); // [100, 200, 300]console.log(newArray); // [200, 400, 600]

6.计算每个类别的数量

const people = [{name: 'John', group: 'A'},{name: 'Andrew', group: 'C'},{name: 'Peter', group: 'A'},{name: 'James', group: 'B'},{name: 'Hanna', group: 'A'},{name: 'Adam', group: 'B'}];
const groupInfo = people.reduce((groups, person) => {const {A = 0, B = 0, C = 0} = groups;if (person.group === 'A') {return {...groups, A: A + 1};} else if (person.group === 'B') {return {...groups, B: B + 1};} else {return {...groups, C: C + 1};}}, {});
console.log(groupInfo); // {A: 3, C: 1, B: 2}

7.根据特定条件检索数组的子集

const myArray = [{x:100}, {x:200}, {x:300}];
const newArray = myArray.filter(element => element.x > 250);console.log(newArray); // [{x:300}]

注意:filter()方法创建一个新数组,其中包含通过所提供函数实现的测试的所有元素。

8.对数组进行排序

const people = [{ name: "John", age: 21 },{ name: "Peter", age: 31 },{ name: "Andrew", age: 29 },{ name: "Thomas", age: 25 }];
let sortByAge = people.sort(function (p1, p2) {return p1.age - p2.age;});
console.log(sortByAge);

在此处输入图片描述

9.在数组中找到一个元素

const people = [ {name: "john", age:23},{name: "john", age:43},{name: "jim", age:101},{name: "bob", age:67} ];
const john = people.find(person => person.name === 'john');console.log(john);

在此处输入图片描述

Array.prototype.find()方法返回数组中满足提供的测试函数的第一个元素的值。

参考文献

如果有人对可用于数组迭代的多种机制的性能方面感兴趣,我准备了以下JSPerf测试:

https://jsperf.com/fastest-array-iterator

性能结果

结果:

传统的for()迭代器是迄今为止最快的方法,尤其是与缓存数组长度一起使用时。

let arr = [1,2,3,4,5];
for(let i=0, size=arr.length; i<size; i++){// Do something}

Array.prototype.forEach()Array.prototype.map()方法是最慢的近似,可能是函数调用开销的结果。

var array = ['hai', 'hello', 'how', 'are', 'you']$(document).ready(function () {$('#clickButton').click(function () {for (var i = 0; i < array.length; i++) {alert(array[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>

正式的(也许是旧的)方法是Array.prototype.forEach(...)

var arr = ["apple", "banana", "cherry", "mango"];arr.forEach(function(item, index, _) {console.log("[" + index + "] = '" + item + "'");});

深奥

let a= ["Hello", "World"];
while(a.length) { console.log( a.shift() ); }

性能测试

今天(2022-11-13)我对Chrome107、Safari15.2和Firefox 106进行了测试。

结论

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

搜索结果

输入图片描述

详情

我执行3个测试:

  • 小型-用于2个元素数组(如OP)-您可以运行它这里
  • 媒体-10K元素数组-你可以运行它这里
  • Big-for100K元素数组-你可以运行它这里

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

function A(a) {let r=0;while(a.length) r+= a.shift().length;return r;}
function B(a) {let r=0;for(i in a) r+= a[i].length;return r;}
function C(a) {let r=0;for(x of a) r+= x.length;return r;}
function D(a) {let r=0;for (i=0; i<a.length; ++i) r+= a[i].length;return r;
}
function E(a) {let r=0;a.forEach(x=> r+= x.length);return r;}
let arr= ["Hello", "World!"];[A,B,C,D,E].forEach(f => console.log(`${f.name}: ${f([...arr])}`))

以下是介质数组Chrome的示例结果:

输入图片描述

JavaScript中的数组遍历备忘单

给定一个数组,您可以通过以下多种方式之一遍历它。

1.经典for

const myArray = ['Hello', 'World'];
for (let i = 0; i < myArray.length; i++) {console.log(myArray[i]);}

2.for...of

const myArray = ['Hello', 'World'];
for (const item of myArray) {console.log(item);}

3.Array.prototype.forEach()

const myArray = ['Hello', 'World'];
myArray.forEach(item => {console.log(item);});

4.while

const myArray = ['Hello', 'World'];let i = 0;
while (i < myArray.length) {console.log(myArray[i]);i++;}

5.do...while

const myArray = ['Hello', 'World'];let i = 0;
do {console.log(myArray[i]);i++;} while (i < myArray.length);

6.队列样式

const myArray = ['Hello', 'World'];

while (myArray.length) {console.log(myArray.shift());}

7.堆栈样式

备注:这个列表反向打印。

const myArray = ['Hello', 'World'];
while (myArray.length) {console.log(myArray.pop());}

//Make arrayvar array = ["1","2","3","4","5","6","7","8","9","10"]//Loopfor(var i = 0; i < array.length; i++){console.log((i+1) + " --> " + array[i])}

对于i的实际数字,如果需要,您需要将(i+1)更改为i(i)
希望有帮助

6种不同的方法循环遍历数组

您可以通过许多不同的方法循环遍历数组。我从上到下整理了我最喜欢的6种方法。

1.使用for循环

当它简单地循环遍历数组时,for循环是我的首选。

let array = [1, 2, 3, 4, 5];for (let i = 0; i < array.length; i++) {console.log(array[i]);}

2.使用foreach循环

forEach循环是一种遍历数组的现代方式。此外,它提供了对数组和元素的更多灵活性和控制。

let array = [1, 2, 3, 4, 5];array.forEach((element) => {console.log(element);});

3.使用for. of

for...of循环让您可以直接访问数组元素。

let array = [1, 2, 3, 4, 5];for (let element of array) {console.log(element);}

4.使用for… in循环

for...in为您提供了一个键,您可以使用它访问数组元素。

let array = [1, 2, 3, 4, 5];for(let index in array){console.log(array[index]);}

5.使用if循环

虽然循环也可用于循环遍历数组。

let array = [1, 2, 3, 4, 5];let length = array.length;while(length > 0){console.log(array[array.length - length]);length--;}

6.使用do…这时循环

同样,我使用do...while循环

let array = [1, 2, 3, 4, 5];let length = array.length;do {console.log(array[array.length - length]);length--;}while (length > 0)

数组迭代有4种方式:

// 1: for
for (let i = 0; i < arr.length; ++i) {console.log(arr[i]);}
// 2: forEach
arr.forEach((v, i) => console.log(v));
// 3: for in
for (let i in arr) {console.log(arr[i]);}
// 4: for of
for (const v of arr) {console.log(v);}

总结:1和3个解决方案创建额外的变量,2-创建额外的函数上下文。最好的方法是第四个-“for of”

考虑这个:

const ITEMS = ['One','Two','Three']let item=-1
//Then, you get looping with every call of:
ITEMS[item=item==ITEMS.length-1?0:item+1]

在javascript中有多种方法可以做到这一点。以下是处理数组的常见方法。

方法一:

const students = ["Arun","Jos","John","Kiran"]for (var index = 0; index < students.length; index++) {console.log(students[index]);}

方法二:

students.forEach((student, index) => console.log(student));

方法三:

for (const student of students) {console.log(student);}  

此答案提供了循环和数组函数的替代方法来迭代数组。

在某些情况下,使用递归实现而不是传统的循环和回调是有意义的。特别是,如果你必须使用多个数组或嵌套数组。你避免编写嵌套循环来访问来自多个数组的数据。我还发现这段代码更容易读写。

/**array is the array your wish to iterate.response is what you want to return.index increments each time the function calls itself.**/
const iterateArray = (array = [], response = [], index = 0) => {const data = array[index]
// If this condition is met. The function returns and stops calling itself.if (!data) {return response}// Do work...response.push("String 1")response.push("String 2")
// Do more work...
// THE FUNCTION CALLS ITSELFiterateArray(data, response, index+=1)}
const mainFunction = () => {const text = ["qwerty", "poiuyt", "zxcvb"]
// Call the recursive functionconst finalText = iterateArray(text)console.log("Final Text: ", finalText()}

假设传递给iterateArray的数组包含对象而不是字符串。每个对象都包含另一个数组。您必须运行嵌套循环才能访问内部数组,但如果您递归迭代,则不会。

您也可以将iterateArray作为Promise。

const iterateArray = (array = [], response = []) =>new Promise(async (resolve, reject) => {const data = array.shift()// If this condition is met, the function returns and stops calling itself.if (!data) {return resolve(response)}
// Do work here...
const apiRequestData = data.innerArray.find((item) => {item.id === data.sub_id})
if (apiRequestData) {try {const axiosResponse = await axios.post("http://example.com",apiRequestData)if (axiosResponse.status === 200) {response.push(apiRequestData)} else {return reject("Data not found")}} catch (error) {reject(error)}} else {return reject("Data not found")}// THE FUNCTION RESOLVES AND CALLS ITSELFresolve(iterateArray(data, response))})