对于JavaScript中的每个数组?
我怎样才能循环使用JavaScript中的数组中的所有条目?
我以为是这样的:
forEach(instance in theArray)
arrays是我的arrays,但这似乎是不正确的。
TL; DR
- 除非您使用保护措施,或者至less知道为什么它会咬你
for-in
否则不要使用原因。 -
你最好的投注通常是
- 一个
for-of
循环(仅限ES2015 +), -
Array#forEach
(spec
|MDN
)(或者它的亲戚等等)(仅限ES5 +), - 一个简单的老式循环,
- 或用保护措施进行。
- 一个
但还有很多东西需要探索,请继续阅读…
JavaScript具有强大的语义来循环访问数组和类似数组的对象。 我已经将答案分为两部分:真正数组的选项,以及类似数组的东西的选项,如arguments
对象,其他可迭代对象(ES2015 +),DOM集合等等。
我很快就会注意到,即使在ES5引擎上,也可以通过将ES2015转换为ES5来使用ES2015选项。 search“ES2015 transpiling”/“ES6 transpiling”查看更多…
好的,让我们看看我们的select:
对于实际数组
在ECMAScript 5 (“ES5”)中有三个选项,目前这个版本得到了最广泛的支持,并且即将在ECMAScript 2015 (ES2015,ES6)中有两个选项,即供应商正在开发的最新版本的JavaScript在支持:
- 使用
forEach
和相关的(ES5 +) - 使用一个简单
for
循环 - 正确使用
for-in
-
for-of
(隐式使用迭代器)(ES2015 +) - 明确使用迭代器(ES2015 +)
细节:
1.使用forEach
和相关的
如果您使用的环境支持ES5的Array
function(直接或使用垫片),则可以使用新的forEach
( spec
| MDN
):
var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); });
forEach
接受一个迭代器函数,可选地,当调用该迭代器函数(以上未使用)时使用this
值。 为数组中的每个条目调用迭代器函数,按顺序跳过稀疏数组中不存在的条目。 尽pipe我只使用了上面的一个参数,但迭代器函数被调用了三个:每个条目的值,该条目的索引,以及对正在迭代的数组的引用(如果函数尚未拥有它便利)。
除非您支持像IE8这样的过时浏览器(截至2016年9月撰写的NetApps市场份额略高于4%),否则您可以在通用的网页中使用forEach
,而无需使用垫片。 如果您确实需要支持过时的浏览器,则可以轻松地完成填充/填充forEach
(针对多个选项search“es5填充”)。
forEach
有一个好处,就是你不必在包含范围中声明索引和值variables,因为它们是作为迭代函数的参数提供的,因此恰好适用于迭代。
如果您担心为每个数组条目进行函数调用的运行时成本,请不要; 细节 。
另外, forEach
是“通过它们全部循环”的function,但ES5定义了其他一些有用的“通过数组和function来工作”的function,其中包括:
-
every
(停止循环第一次迭代器返回false
或falsey) -
some
(停止循环第一次迭代器返回true
或truthy) -
filter
(创build一个新的数组,包括filter函数返回true
元素,并省略返回false
元素) -
map
(由迭代器函数返回的值创build一个新的数组) -
reduce
(通过重复调用迭代器来build立一个值,传入以前的值;参见spec的细节;对于数组的内容和许多其他的东西是有用的) -
reduceRight
(像reduce
,但工作在降序而不是升序)
2.使用一个简单for
循环
有时旧的方式是最好的:
var index; var a = ["a", "b", "c"]; for (index = 0; index < a.length; ++index) { console.log(a[index]); }
如果在循环过程中arrays的长度不会改变,并且它在性能敏感的代码中(不太可能),稍微复杂一点的版本可能会稍微快一点:
var index, len; var a = ["a", "b", "c"]; for (index = 0, len = a.length; index < len; ++index) { console.log(a[index]); }
和/或倒计时:
var index; var a = ["a", "b", "c"]; for (index = a.length - 1; index >= 0; --index) { console.log(a[index]); }
但是用现代的JavaScript引擎,很less有你需要去掉最后一滴果汁。
在ES2015及更高版本中,可以使您的索引和值variables局部用于for
循环:
let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; } //console.log(index); // Would cause "ReferenceError: index is not defined" //console.log(value); // Would cause "ReferenceError: value is not defined"
当你这样做的时候,不仅仅是value
而且还为每个循环迭代重新创buildindex
,这意味着在循环体中创build的闭包保持对为特定迭代创build的index
(和value
)的引用:
let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { alert("Index is: " + index); }); }
如果你有五个div,如果你点击第一个,你会得到“Index is:0”,如果你点击了最后一个,你会得到“Index is:4”。 如果你使用var
而不是let
这是行不通的。
3. 正确使用for-in
你会让人们告诉你使用for-in
,但这不是for-in
目的 。 for-in
循环通过对象的可枚举属性 ,而不是数组的索引。 订单不能保证 ,即使在ES2015(ES6)中也是如此。 ES2015没有定义对象属性的顺序(通过[[OwnPropertyKeys]]
, [[Enumerate]]
以及像Object.getOwnPropertyKeys
那样使用它们的东西),但是它没有定义for-in
将遵循该顺序。 (在这个其他答案的细节。)
不过,如果使用适当的安全措施,它可能会很有用,特别是对于稀疏数组 :
// `a` is a sparse array var key; var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (key in a) { if (a.hasOwnProperty(key) && // These are explained /^0$|^[1-9]\d*$/.test(key) && // and then hidden key <= 4294967294 // away below ) { console.log(a[key]); } }
注意两个检查:
-
对象有自己的名字(不是从它的原型inheritance的),和
-
密钥是以普通stringforms的基数为10的数字string,其值为<= 2 ^ 32 – 2(即4,294,967,294)。 这个数字来自哪里? 它是规范中数组索引定义的一部分。 其他数字(非整数,负数,大于2 ^ 32 – 2的数字)不是数组索引。 2 ^ 32 – 2的原因是使得最大的索引值低于2 ^ 32 – 1 ,这是数组
length
可以达到的最大值。 (例如,一个数组的长度符合一个32位的无符号整数。) (道具RobG指出在我的博客文章的评论,我以前的testing是不正确的。)
在大多数数组上,每循环迭代都会增加一点额外的开销,但是如果你有一个稀疏数组,它可能是一种更有效的循环方式,因为它只循环实际存在的条目。 例如,对于上面的数组,我们总共循环三次(对于键"0"
, "10"
和"10000"
– 记住,它们是string),而不是10,001次。
现在,你不会每次写这个,所以你可以把它放在你的工具箱里:
function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2 }
然后我们会这样使用它:
for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } }
或者,如果您只对“大多数情况下的testing”感兴趣,则可以使用这个testing,但是当它接近时,则不太正确:
for (key in a) { // "Good enough" for most cases if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) { console.log(a[key]); } }
4.使用for-of
(隐式使用迭代器)(ES2015 +)
ES2015将迭代器添加到JavaScript中。 使用迭代器最简单的方法是新的for-of
语句。 它看起来像这样:
var val; var a = ["a", "b", "c"]; for (val of a) { console.log(val); }
输出:
一个 b C
在封面下,从数组中获取一个迭代器并循环,从中获取值。 这没有使用for-in
问题,因为它使用由对象(数组)定义的迭代器,并且数组定义迭代器迭代其条目 (而不是它们的属性)。 与ES5中的for-in
不同for-in
条目访问的顺序是其索引的数字顺序。
5.明确使用迭代器(ES2015 +)
有时候,你可能想明确地使用一个迭代器。 你也可以做到这一点,虽然它比原来要笨得多。 它看起来像这样:
var a = ["a", "b", "c"]; var it = a.values(); var entry; while (!(entry = it.next()).done) { console.log(entry.value); }
迭代器是一个函数(具体来说是一个生成器 ),每当你next
一次调用时都会返回一个新的对象。 迭代器返回的对象有一个属性done
,告诉我们它是否完成,以及具有该迭代值的属性value
。
value
的含义取决于迭代器; 数组支持(至less)三个返回迭代器的函数:
-
values()
:这是我在上面使用的。 它返回一个迭代器,其中每个value
都是该迭代的值。 -
keys()
:返回一个迭代器,其中每个value
都是该迭代的关键(对于上面的我们来说,这将是"0"
,然后是"1"
,然后是"2"
)。 -
entries()
:返回一个迭代器,其中每个value
都是该迭代forms为[key, value]
的数组。
(在撰写本文时,Firefox 29支持entries
和keys
但不支持values
。)
对于类似于数组的对象
除了真正的数组之外,还有一些类似数组的对象,它们具有length
属性和带有数字名称的属性: NodeList
实例, arguments
对象等。我们如何遍历它们的内容?
使用上面的任何选项作为数组
至less有一些,甚至可能是大部分甚至全部的数组方法经常同样适用于类似数组的对象:
-
使用
forEach
和相关的(ES5 +)Array.prototype
上的各种函数是“有意通用的”,通常可以通过Function#call
或Function#apply
类似数组的对象上Function#apply
。 (在这个答案的最后,请参阅警告提供主机提供的对象 ,但这是一个罕见的问题。)假设你想在
Node
的childNodes
属性上使用forEach
。 你会这样做:Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with `child` });
如果你打算这么做的话,你可能想把一个函数引用的副本拷贝到一个variables中以供重用,例如:
// (This is all presumably in some scoping function) var forEach = Array.prototype.forEach; // Then later... forEach.call(node.childNodes, function(child) { // Do something with `child` });
-
使用一个简单
for
循环显然,一个简单的
for
循环适用于类似数组的对象。 -
正确使用
for-in
如果使用与数组相同的保护措施,则也应该使用类似数组的对象; 上面#1的主机提供的对象的警告可能适用。
-
for-of
(隐式使用迭代器)(ES2015 +)for-of
将使用由对象提供的迭代器(如果有的话); 我们将不得不看看它如何与各种类似arrays的对象,特别是主机提供的对象一起使用。 -
明确使用迭代器(ES2015 +)
见#4,我们将看看迭代器如何发挥。
创build一个真正的数组
其他时候,你可能想要将一个类似数组的对象转换成一个真正的数组。 这样做非常简单:
-
使用数组的
slice
方法我们可以使用数组的
slice
方法,就像上面提到的其他方法是“有意通用的”,所以可以像数组一样使用,就像这样:var trueArray = Array.prototype.slice.call(arrayLikeObject);
所以
NodeList
例子,如果我们想把一个NodeList
转换成一个真正的数组,我们可以这样做:var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
请参阅下面的主机提供的对象注意事项 。 尤其要注意的是,在IE8和更早的版本中,这将会失败,因为它不允许使用主机提供的对象。
-
使用传播符号(
...
)也可以使用ES2015的扩展表示法 (MDN目前称之为操作员;它不是),使用支持该function的JavaScript引擎:
var trueArray = [...iterableObject];
所以举例来说,如果我们想要把一个
NodeList
转换成一个真正的数组,用扩展的语法,这个变得非常简洁:var divs = [...document.querySelectorAll("div")];
-
使用
Array.from
(spec) | (MDN)Array.from
(ES2015,但是shimmable)从一个类似数组的对象中创build一个数组,可选地首先通过映射函数传递这些条目。 所以:var divs = Array.from(document.querySelectorAll("div"));
或者,如果你想获得给定类的元素的标签名称数组,你可以使用映射函数:
// Arrow function (ES2015): var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName); // Standard function (since `Array.from` can be shimmed): var divs = Array.from(document.querySelectorAll(".some-class"), function(element) { return element.tagName; });
注意主机提供的对象
如果您将Array.prototype
函数与主机提供的类似数组的对象(DOM列表和其他由浏览器而不是JavaScript引擎提供的东西)一起使用,则需要确保在目标环境中进行testing,以确保主机提供的对象行为正常。 大多数人的行为是正确的 (现在),但是testing是很重要的。 原因是你可能想要使用的大多数Array.prototype
方法依赖于主机提供的对象,给出了抽象[[HasProperty]]
操作的一个诚实的答案。 在撰写本文时,浏览器做了很好的工作,但是ES5规范确实允许主机提供的对象可能不是诚实的; 它在§8.6.2 (在该部分开始附近的大表格下面几段)中,它说:
主机对象可以以任何方式实现这些内部方法,除非另有规定; 例如,一种可能性是特定主机对象的
[[Get]]
和[[Put]]
确实获取并存储属性值,但[[HasProperty]]
总是生成false 。
(我在ES2015规范中找不到等价的语言,但它仍然是这种情况。)再次,在写这篇文章的时候,在现代浏览器(例如NodeList
实例)中,通用主机提供的类似于数组的对象正确处理[[HasProperty]]
,但testing是很重要的。
编辑 :这个答案是绝望的过时。 对于更现代的方法,请查看数组上可用的方法 。 感兴趣的方法可能是:
- 的forEach
- 地图
- 过滤
- 压缩
- 减less
- 一切
- 一些
在JavaScript中迭代一个数组的标准方法是一个for
循环的vanilla:
var length = arr.length, element = null; for (var i = 0; i < length; i++) { element = arr[i]; // Do something with element i. }
但是,请注意,如果您有一个密集的数组,并且每个索引都被一个元素占据,那么这种方法才是有效的。 如果数组是稀疏的,那么你可能会遇到这种方法的性能问题,因为你将遍历数组中不存在的很多索引。 在这种情况下, for .. in
-loop可能是一个更好的主意。 但是 ,您必须使用适当的安全措施来确保仅对数组(即数组元素)所需的属性起作用,因为for..in
-loop也将在旧版浏览器中枚举,或者如果额外属性被定义为enumerable
。
在ECMAScript 5中 ,数组原型上会有一个forEach方法,但在传统浏览器中不支持。 所以为了能够一致地使用它,你必须有一个支持它的环境(例如,服务器端JavaScript的Node.js ),或者使用“Polyfill”。 然而,这个function的填充是微不足道的,因为它使代码更容易阅读,这是一个很好的polyfill包括。
如果你使用jQuery库,你可以使用jQuery.each :
$.each(yourArray, function(index, value) { // do your stuff here });
编辑:
按照每个问题,用户想在JavaScript代码而不是jQuery,所以编辑
var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. }
向后循环
我认为这个循环的反面值得一提:
for (var i = array.length; i--; ) { // process array[i] }
优点:
- 你不需要声明一个临时的
len
variables,或者在每次迭代时比较array.length
,这两者都可能是一个微小的优化。 - 以相反的顺序从DOM中删除兄弟姐妹通常更有效 。 (浏览器需要在内部arrays中减less元素的移动。)
- 如果在循环时修改数组 ,或者在索引i之后 (例如在
array[i]
处删除或插入项),则前向循环会跳过左移到位置i的项 ,或者重新处理i这个东西是右移的。 在传统的for循环中,可以将 i更新为指向需要处理的下一个项目 – 1,但是简单地颠倒迭代的方向通常是更简单 更优雅的解决scheme 。 - 同样,修改或移除嵌套的 DOM元素时,反向处理可以规避错误 。 例如,考虑在处理子节点之前修改父节点的innerHTML。 到达子节点时,它将从DOM中分离出来,当父节点的innerHTML被写入时,被新创build的子节点replace。
- 打字和阅读的时间比其他一些可用选项短 。 虽然它损失
forEach()
和ES6的for ... of
缺点:
- 它按相反顺序处理项目。 如果你从结果中创build一个新的数组,或者在屏幕上打印一些东西, 那么输出结果自然会相对于原来的顺序颠倒过来 。
- 反复插入兄弟姐妹作为第一个孩子,以保持其秩序效率较低 。 (浏览器将不得不正确地移动东西。)为了有效地创buildDOM节点,按照正常的方式向前循环并追加(也使用“文档片段”)。
- 反向循环让初级开发者感到困惑 。 (你可能会认为这是一个优势,取决于你的前景。)
我应该一直使用它吗?
有些开发人员默认情况下使用反向循环,除非有充分的理由向前循环。
虽然performance收益通常微不足道,但有点尖叫:
“只要对列表中的每个项目都这样做,我不关心订单!”
然而在实践中,这实际上并不是一个可靠的意向指示,因为它与那些关心订单的场合没有什么区别,而且确实需要反向循环。 所以实际上,还需要另外一个构造来准确地expression“不关心”的意图,这在大多数语言中是不可用的,包括ECMAScript,但是可以被称为forEachUnordered()
。
如果顺序无关紧要,并且效率是一个问题(在游戏或animation引擎的最内层循环中),那么使用reverse for loop作为您的前往模式也是可以接受的。 只要记住在现有的代码中看到一个反向的循环并不一定意味着这个命令是不相关的!
最好使用forEach()
一般来说,对于清晰度和安全性较高的高层代码,我build议使用Array::forEach
作为默认模式:
- 阅读很清楚。
- 这表明我不会在这个区块内移动(这总是隐藏在漫长
for
循环中)。 - 它给你一个免费的封闭范围。
- 它减less了局部variables的泄漏以及与外部variables的(和变异的)意外碰撞。
然后当你看到你的代码中的循环反转,这是一个暗示,这是一个很好的理由(也许是上述原因之一)颠倒。 而看到一个传统的前进循环可能表明,转移可以发生。
(如果对意图的讨论对你没有任何意义,那么你和你的代码可以从观看Crockford关于编程风格和你的大脑的讲座中获益。)
它是如何工作的?
for (var i = 0; i < array.length; i++) { ... } // Forwards for (var i = array.length; i--; ) { ... } // Reverse
你会注意到i--
是中间语句(我们通常会看到一个比较),最后一个语句是空的(我们经常看到i++
)。 这意味着我也被用作延续的条件 。 至关重要的是,它在每次迭代之前被执行和检查。
-
如何从
array.length
开始而不爆炸?因为
i--
在每次迭代之前运行,所以在第一次迭代中,我们将实际访问array.length - 1
的项目,这样可以避免任何有关数组越界undefined
项目的问题。 -
为什么不停止在索引0之前迭代?
当条件i评估为假值(当它产生0)时,循环将停止迭代。
关键是不像
--i
,后面的i--
操作符递减i
但在递减之前产生值。 你的控制台可以演示这个:> var i = 5; [i, i--, i];
[5, 5, 4]
所以在最后一次迭代中, 我以前是1 ,而
i--
expression式将其更改为0,但实际上产生1 (truthy),所以条件通过。 在下一次迭代中,i--
将我更改为-1,但产生0 (falsey),导致执行立即从循环底部删除。在传统的循环中,
i++
和++i
是可以互换的(正如Douglas Crockford所指出的那样)。 然而,在循环的反面,因为我们的递减也是我们的条件expression式,所以我们必须坚持我 – 如果我们要处理在索引0的项目。
琐事
有些人喜欢在相反for
循环中绘制一个小箭头,并以一个眨眼结束:
for (var i = array.length; i --> 0 ;) {
为了向我展示反向循环的好处和恐怖,我们向WYL发放了积分。
一些C风格的语言使用foreach
循环枚举。 在JavaScript中,这是用for..in
循环结构完成的 :
var index, value; for (index in obj) { value = obj[index]; }
有一个问题。 for..in
将for..in
每个对象的可枚举成员以及其原型上的成员。 为了避免读取通过对象原型inheritance的值,只需检查属性是否属于该对象:
for (i in obj) { if (obj.hasOwnProperty(i)) { //do stuff } }
此外, ECMAScript 5已经将一个forEach
方法添加到Array.prototype
,该方法可以使用callback对数组进行枚举(polyfill位于文档中,因此您仍可以将其用于旧版浏览器):
arr.forEach(function (val, index, theArray) { //do stuff });
请注意,当callback返回false
时Array.prototype.forEach
不会中断。 jQuery和Underscore.js提供了各自的变体,以提供可以短路的环路。
如果你想循环一个数组,使用标准的三部分for
循环。
for (var i = 0; i < myArray.length; i++) { var arrayItem = myArray[i]; }
您可以通过cachingmyArray.length
或向后迭代来获得性能优化。
forEach实现( 请参阅jsFiddle ):
function forEach(list,callback) { var length = list.length; for (var n = 0; n < length; n++) { callback.call(list[n]); } } var myArray = ['hello','world']; forEach( myArray, function(){ alert(this); // do something } );
如果您不介意清空数组:
var x; while(x = y.pop()){ alert(x); //do something }
x
将包含y
的最后一个值,它将从数组中移除。 你也可以使用shift()
来移除y
中的第一项。
我知道这是一个旧的post,已经有很多很好的答案。 为了更完整一些,我想我会用另一个AngularJS 。 当然,这只适用于使用Angular的情况,显然,尽pipe如此,我还是想说。
angular.forEach
需要2个参数和一个可选的第三个参数。 第一个参数是要迭代的对象(数组),第二个参数是迭代器函数,可选的第三个参数是对象上下文(在循环内部基本上称为“this”)。
有不同的方法来使用forEach循环的angular度。 最简单也是最常用的是
var temp = [1, 2, 3]; angular.forEach(temp, function(item) { //item will be each element in the array //do something });
另一种有用的方法是将项目从一个数组复制到另一个数组
var temp = [1, 2, 3]; var temp2 = []; angular.forEach(temp, function(item) { this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2. }, temp2);
Though, you don't have to do that, you can simply do the following and it's equivalent to the previous example:
angular.forEach(temp, function(item) { temp2.push(item); });
Now there are pros and cons of using the angular.forEach
function as opposed to the built in vanilla-flavored for
loop.
优点
- Easy readability
- Easy writability
- If available,
angular.forEach
will use the ES5 forEach loop. Now, I will get to efficientcy in the cons section, as the forEach loops are much slower than the for loops. I mention this as a pro because it's nice to be consistent and standardized.
Consider the following 2 nested loops, which do exactly the same thing. Let's say that we have 2 arrays of objects and each object contains an array of results, each of which has a Value property that's a string (or whatever). And let's say we need to iterate over each of the results and if they're equal then perform some action:
angular.forEach(obj1.results, function(result1) { angular.forEach(obj2.results, function(result2) { if (result1.Value === result2.Value) { //do something } }); }); //exact same with a for loop for (var i = 0; i < obj1.results.length; i++) { for (var j = 0; j < obj2.results.length; j++) { if (obj1.results[i].Value === obj2.results[j].Value) { //do something } } }
Granted this is a very simple hypothetical example, but I've written triple embedded for loops using the second approach and it was very hard to read, and write for that matter.
缺点
- 效率。
angular.forEach
, and the nativeforEach
, for that matter, are both so much slower than the normalfor
loop….about 90% slower . So for large data sets, best to stick to the nativefor
loop. - No break, continue, or return support.
continue
is actually supported by " accident ", to continue in anangular.forEach
you simple put areturn;
statement in the function likeangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
which will cause it to continue out of the function for that iteration. This is also due to the fact that the nativeforEach
does not support break or continue either.
I'm sure there's various other pros and cons as well, and please feel free to add any that you see fit. I feel that, bottom line, if you need efficiency, stick with just the native for
loop for your looping needs. But, if your datasets are smaller and a some efficiency is okay to give up in exchange for readability and writability, then by all means throw an angular.forEach
in that bad boy.
An easy solution now would be to use the underscore.js library . It's providing many useful tools, such as each
and will automatically delegate the job to the native forEach
if available.
A CodePen example of how it works is:
var arr = ["elemA", "elemB", "elemC"]; _.each(arr, function(elem, index, ar) { ... });
也可以看看
- Documentation for native
Array.prototype.forEach()
. - In for_each…in (MDN) it is explained that
for each (variable in object)
is deprecated as the part of ECMA-357 ( EAX ) standard. - for…of (MDN) describes the next way of iterating using
for (variable of object)
as the part of the Harmony (ECMAScript 6) proposal.
Probably the for(i = 0; i < array.length; i++)
loop is not the best choice. 为什么? If you have this:
var array = new Array(); array[1] = "Hello"; array[7] = "World"; array[11] = "!";
The method will call from array[0]
to array[2]
. First, this will first reference variables you don't even have, second you would not have the variables in the array, and third this will make the code bolder. Look here, it's what I use:
for(var i in array){ var el = array[i]; //If you want 'i' to be INT just put parseInt(i) //Do something with el }
And if you want it to be a function, you can do this:
function foreach(array, call){ for(var i in array){ call(array[i]); } }
If you want to break, a little more logic:
function foreach(array, call){ for(var i in array){ if(call(array[i]) == false){ break; } } }
例:
foreach(array, function(el){ if(el != "!"){ console.log(el); } else { console.log(el+"!!"); } });
It returns:
//Hello //World //!!!
There are three implementations of foreach
in jQuery as follows.
var a = [3,2]; $(a).each(function(){console.log(this.valueOf())}); //Method 1 $.each(a, function(){console.log(this.valueOf())}); //Method 2 $.each($(a), function(){console.log(this.valueOf())}); //Method 3
As of ES6:
list = [0, 1, 2, 3] for (let obj of list) { console.log(obj) }
There isn't any for each
loop in native JavaScript . You can either use libraries to get this functionality (I recommend Underscore.js ), use a simple for
in loop.
for (var instance in objects) { ... }
However, note that there may be reasons to use an even simpler for
loop (see Stack Overflow question Why is using “for…in” with array iteration such a bad idea? )
var instance; for (var i=0; i < objects.length; i++) { var instance = objects[i]; ... }
This is an iterator for NON-sparse list where the index starts at 0, which is the typical scenario when dealing with document.getElementsByTagName or document.querySelectorAll)
function each( fn, data ) { if(typeof fn == 'string') eval('fn = function(data, i){' + fn + '}'); for(var i=0, L=this.length; i < L; i++) fn.call( this[i], data, i ); return this; } Array.prototype.each = each;
Examples of usage:
Example #1
var arr = []; [1, 2, 3].each( function(a){ a.push( this * this}, arr); arr = [1, 4, 9]
Example #2
each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');
Each p tag gets class="blue"
Example #3
each.call(document.getElementsByTagName('p'), "if( i % 2 == 0) this.className = data;", 'red' );
Every other p tag gets class="red"
>
Example #4
each.call(document.querySelectorAll('p.blue'), function(newClass, i) { if( i < 20 ) this.className = newClass; }, 'green' );
And finally the first 20 blue p tags are changed to green
Caution when using string as function: the function is created out-of-context and ought to be used only where you are certain of variable scoping. Otherwise, better to pass functions where scoping is more intuitive.
There's no inbuilt ability to break in forEach
. To interrupt execution use the Array#some
like below:
[1,2,3].some(function(number) { return number === 1; });
This works because some
returns true as soon as any of the callbacks, executed in array order, returns true, short-circuiting the execution of the rest. Original Answer see Array prototype for some
ECMAScript5 (the version on Javascript) to work with Arrays.
forEach – Iterates through every item in the array and do whatever you need with each item.
['C', 'D', 'E'].forEach(function(element, index) { console.log(element + " is the #" + (index+1) + " in musical scale"); }); // Output // C is the #1 in musical scale // D is the #2 in musical scale // E is the #3 in musical scale
In case , more interested on operation on array using some inbuilt feature.
map – It creates a new array with the result of the callback function. This method is good to be used when you need to format the elements of your array.
// Let's upper case the items in the array ['bob', 'joe', 'jen'].map(function(elem) { return elem.toUpperCase(); }); // Output: ['BOB', 'JOE', 'JEN']
reduce – As the name says it reduces the array to a single value by calling the given function passing in the currenct element and the result of the previous execution.
[1,2,3,4].reduce(function(previous, current) { return previous + current; }); // Output: 10 // 1st iteration: previous=1, current=2 => result=3 // 2nd iteration: previous=3, current=3 => result=6 // 3rd iteration: previous=6, current=4 => result=10
every – Returns true or false if all the elements in the array pass the test in the callback function.
// Check if everybody has 18 years old of more. var ages = [30, 43, 18, 5]; ages.every(function(elem) { return elem >= 18; }); // Output: false
filter – Very similar to every except that filter return an array with the elements that return true to the given function.
// Finding the even numbers [1,2,3,4,5,6].filter(function(elem){ return (elem % 2 == 0) }); // Output: [2,4,6]
Hope this will be useful.
There are a few ways to loop through an array in JavaScript, as below:
for – it's the most common one. Full block of code for looping
var languages = ["JAVA", "JavaScript", "C#", "Python"]; var i, len, text; for (i = 0, len = languages.length, text = ""; i < len; i++) { text += languages[i] + "<br>"; } document.getElementById("example").innerHTML = text;
<p id="example"></p>
jQuery way using $.map
:
var data = [1, 2, 3, 4, 5, 6, 7]; var newData = $.map(data, function(element) { if (element % 2 == 0) { return element; } }); // newData = [2, 4, 6];
I also would like to add this as a composition of a reverse loop and an answer above for someone that would like this syntax too.
var foo = [object,object,object]; for (var i = foo.length, item; item = foo[--i];) { console.log(item); }
优点:
The benefit for this: You have the reference already in the first like that won't need to be declared later with another line. It is handy when looping trough the object array.
缺点:
This will break whenever the reference is false – falsey (undefined, etc.). It can be used as an advantage though. However, it would make it a little bit harder to read.
A way closest to your idea would be to use Array.forEach()
which accepts a clojure function wich will be executed for each element of the array.
myArray.forEach( (item) => { // do something console.log(item); } );
Another viable way would be to use Array.map()
which works in the same way but also mutates
each element and returns it like:
var myArray = [1, 2, 3]; myArray = myArray.map( (item) => { return item + 1; } ); console.log(myArray); // [2, 3, 4]
The lambda syntax doesnt usually work in IE 10 or below.
I usually use the
[].forEach.call(function(value,index){ console.log("value of the looped element" + value); console.log("index of the looped element" + index); }); If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters $("#ul>li").each(function(**index,value**){ console.log("value of the looped element" + value); console.log("index of the looped element" + index); });