提问



如何使用JavaScript循环遍历数组中的所有条目?


我以为它是这样的:


forEach(instance in theArray)


theArray是我的阵列,但这似乎是不正确的。

最佳参考




TL; DR



  • 不要使用for-in,除非你在保护措施中使用它或者至少知道它为什么会咬你。

  • 通常是你最好的赌注



    • 一个for-of循环(仅限ES2015 +),

    • Array#forEach(spec | MDN)(或其亲属some等)(仅限ES5 +),

    • 一个简单的老式for循环,

    • for-in有保障措施。




但是要探索更多很多,请继续阅读...... [278] [279]





JavaScript具有强大的语义,可以循环遍历数组和类似数组的对象。我将答案分为两部分:正版数组的选项,以及像这样的数组的选项,例如arguments对象,其他可迭代对象(ES2015 +), DOM集合等。


我将很快注意到您可以使用ES2015选项现在,即使在ES5引擎上,通过转换 ES2015到ES5。搜索ES2015 transpiling/ES6 transpiling更多......


好的,让我们来看看我们的选择:


对于实际阵列



你有三个选项ECMAScript  5(ES5),目前支持最广泛的版本,很快将在ECMAScript 2015(ES2015,ES6)中再增加两个,这是供应商提供的最新版JavaScript正致力于支持:[280] [281]



  1. 使用forEach及相关(ES5 +)

  2. 使用简单的for循环

  3. 正确使用for-in

  4. 使用for-of(隐式使用迭代器)(ES2015 +)

  5. 明确使用迭代器(ES2015 +)



细节:


1。使用forEach和相关的



如果您正在使用支持ES5 Array功能的环境(直接或使用填充程序),则可以使用新的forEach(spec | MDN): [282] [283]


var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});


forEach接受迭代器函数,并且可选地,在调用迭代器函数时使用this作为值(上面未使用)。为数组中的每个条目调用迭代器函数,按顺序跳过稀疏数组中不存在的条目。虽然我上面只使用了一个参数,但迭代器函数用三个调用:每个条目的值,该条目的索引,以及对你重复迭代的数组的引用(如果你的函数还没有它的话)便利)。


除非你支持像IE8这样过时的浏览器(截至2016年9月,NetApps的市场份额仅超过4%),你可以愉快地在没有垫片的通用网页中使用forEach。如果你确实需要支持过时的浏览器,可以轻松完成填充/填充forEach(为几个选项搜索es5 shim)。


forEach的好处是你不必在包含范围内声明索引和值变量,因为它们作为迭代函数的参数提供,因此很好地限定了该迭代。


如果您担心为每个数组条目调用函数的运行时成本,请不要这样做;的信息。[284]


另外,forEach是循环通过它们的功能,但ES5定义了其他一些有用的按照你的方式完成数组并做事的功能,包括:



  • every(第一次迭代器返回false或者假的时候停止循环)

  • some(第一次迭代器返回true或者其他东西时停止循环)

  • filter(创建一个新数组,包括过滤函数返回true的元素,省略返回false的那些元素)

  • map(根据迭代器函数返回的值创建一个新数组)

  • reduce(通过重复调用迭代器来构建一个值,传入以前的值;查看详细信息的规范;对于汇总数组的内容和许多其他内容很有用)

  • reduceRight(如reduce,但按降序而非降序工作)



2。使用简单的for循环



有时旧的方式是最好的:[285] [286] [287] [288] [289] [290]


var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
    console.log(a[index]);
}


如果数组的长度在循环期间不会发生变化,而且在性能敏感的代码中(不太可能),那么在前面抓取长度的稍微复杂的版本可能是 tiny 更快一点:


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引擎,你很少需要榨取最后一点果汁。


在ES2015及更高版本中,您可以将索引和值变量设置为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而且index被重新创建用于每个循环迭代,这意味着在循环体中创建的闭包保持对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,你得到索引是:0,如果你点击了第一个,索引是:4,如果你点击了最后一个。如果你使用[[strong>不]] 111]]而不是let


3。正确使用for-in



你会让人们告诉你使用for-in,但这不是for-in的用途。 for-in遍历对象的可枚举属性,而不是数组的索引。 订单无法保证,即使在ES2015(ES6)中也是如此。 ES2015确实定义了对象属性的顺序(通过[**OwnPropertyKeys**][**Enumerate**],以及使用它们的东西,如Object.getOwnPropertyKeys),但定义for-in将遵循该命令。 (另一个答案详述。)[291] [292] [293] [294]


尽管如此,可以有用,特别是对于稀疏数组,如果你使用适当的安全措施:[296]


// `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]);
    }
}


请注意两个检查:



  1. 该对象具有该名称的拥有属性(不是从其原型继承的属性),并且

  2. 该密钥是普通字符串形式的基数为10的数字字符串,其值为<=2 ^ 32 - 2(即4,294,967,294)。这个数字来自哪里?它是规范中数组索引定义的一部分。其他数字(非整数,负数,大于2 ^ 32 - 2的数字)不是数组索引。它的原因是2 ^ 32 - 2 使得最大索引值低于2 ^ 32 - 1 ,这是数组s length可以具有的最大值。例如,数组的长度适合32位无符号整数。)(Props to RobG在我的博客文章评论中指出我以前的测试不是很正确。) [297]]] [298]



在大多数阵列上,每次循环迭代都会增加一小部分开销,但如果你有一个稀疏数组,它可以是一种更有效的循环方式,因为它只会循环实际存在的条目。例如,对于上面的数组,我们总共循环三次(对于键"0""10""10000" —记住,它们是字符串,而不是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]);
    }
}


或者,如果你对大多数情况下足够好的测试感兴趣,你可以使用它,但是当它接近时,它不太正确:


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


输出:


a
b
c


在封面下,从数组中获取迭代器并循环遍历它,从中获取值。这没有使用for-in的问题,因为它使用由对象(数组)定义的迭代器,并且数组定义它们的迭代器迭代它们的条目(不是它们的与ES5中的for-in不同,访问条目的顺序是其索引的数字顺序。


5。明确使用迭代器(ES2015 +)



有时,您可能希望显式使用迭代器 。你也可以这样做,虽然它比for-of更笨拙。它看起来像这样:


var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}


迭代器是一个函数(特别是生成器),每次调用next时都会返回一个新对象。迭代器返回的对象有一个属性done,它告诉我们它是否完成,以及一个带有该迭代值的属性value


value的含义取决于迭代器;数组支持(至少)三个返回迭代器的函数:



  • values():这是我上面使用的那个。它返回一个迭代器,其中每个value是该迭代的值。

  • keys():返回一个迭代器,其中每个value是该迭代的关键(因此对于上面的a,那将是"0",然后是"1"]],然后"2")。

  • entries():返回一个迭代器,其中每个value是一个[key, value]形式的数组,用于该迭代。



(截至撰写本文时,Firefox 29支持entrieskeys但不支持values。)


对于类似数组的对象



除了真正的数组之外,还有类似数组的对象具有length属性和具有数字名称的属性:NodeList实例,arguments对象等我们如何循环其内容?


使用上面的任何数组选项



上面的阵列方法中的至少一些,可能是大多数甚至全部,经常同样适用于类似数组的对象:



  1. 使用forEach和相关(ES5 +)


    Array.prototype上的各种函数是故意通用的,通常可以通过Function#callFunction#apply用于类似数组的对象。 (请参阅本答案末尾的警告,了解主机提供的对象,但这是一个罕见的问题。)[299] [300]


    假设你想在NodechildNodes属性上使用forEach。你这样做:


    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    


    如果您要做很​​多事情,可能需要将函数引用的副本复制到变量中以便重用,例如:


    // (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`
    });
    

  2. 使用简单的for循环


    显然,一个简单的for循环适用于类似数组的对象。

  3. 正确使用for-in


    for-in具有与数组相同的安全措施也应该使用类似数组的对象;上面#1上主机提供的对象的警告可能适用。

  4. 使用for-of(隐式使用迭代器)(ES2015 +)


    for-of将使用对象提供的迭代器(如果有的话);我们将不得不看到它如何与各种类似阵列的对象一起使用,特别是主机提供的对象。

  5. 明确使用迭代器(ES2015 +)


    看到#4,我们将不得不看看迭代器如何发挥作用。



创建一个真正的数组



其他时候,您可能希望将类似数组的对象转换为真正的数组。这样做非常简单:



  1. 使用数组的slice方法 [301]


    我们可以使用数组的slice方法,它与上面提到的其他方法一样是故意通用的,因此可以与类似数组的对象一起使用,如下所示:


    var trueArray = Array.prototype.slice.call(arrayLikeObject);
    


    因此,例如,如果我们想将NodeList转换为真正的数组,我们可以这样做:


    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    


    请参阅下面的警告,了解主机提供的对象。特别要注意的是,这将在IE8及更早版本中失败,这不会让你像这样使用主机提供的对象this

  2. 使用点差表示法[[...) [302]


    它也可以使用ES2015的扩展符号(MDN目前称它为运算符;它不是一个),JavaScript引擎支持此功能:[303]


    var trueArray = [...iterableObject];
    


    因此,例如,如果我们想将NodeList转换为真正的数组,使用扩展语法,这变得非常简洁:


    var divs = [...document.querySelectorAll("div")];
    

  3. 使用Array.from (规范)| (MDN)[304] [305]


    Array.from(ES2015,但可调整)从类似数组的对象创建一个数组,可选择首先通过映射函数传递条目。所以:


    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引擎)一起使用,则需要确保在目标环境,以确保主机提供的对象行为正常。 大多数行为正常(现在),但测试非常重要。原因是您可能想要使用的大多数Array.prototype方法都依赖于主机提供的对象给出抽象[**HasProperty**]操作的诚实答案。在撰写本文时,浏览器在这方面做得非常好,但ES5规范确实允许主机提供的对象可能不诚实;它出现在§8.6.2(该部分开头附近的大表下面几段),其中说:[306] [307]



  除非另有说明,否则Host对象可以以任何方式实现这些内部方法;例如,一种可能性是特定主机对象的[**Get**][**Put**]确实获取并存储属性值,但[**HasProperty**]总是生成 false



(我无法在ES2015规范中找到相同的措辞,但它仍然必然如此。)同样,在撰写本文时,现代浏览器中常见的主机提供的类似数组的对象(NodeList实例,例如)执行正确处理[**HasProperty**],但测试很重要。

其它参考1


修改:这个答案毫无希望地过时了。有关更现代的方法,请查看阵列上可用的方法。感兴趣的方法可能是:[308]



  • 的forEach

  • 地图

  • 过滤

  • 拉链

  • 减少

  • 每个

  • 一些






在JavaScript中迭代数组的标准方法是vanilla for - 循环:[309]


var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element i.
}


但请注意,只有拥有密集数组且每个索引都被一个元素占用时,此方法才有用。如果数组是稀疏的,那么使用这种方法可能会遇到性能问题,因为您将迭代许多真正存在于数组中的索引。在这种情况下,for .. in - 循环可能是一个更好的主意。 但是,您必须使用适当的安全措施来确保只对数组所需的属性(即数组元素)起作用,因为for..in - 循环也将被枚举在旧版浏览器中,或者如果其他属性定义为enumerable​​]]。


在ECMAScript 5中,阵列原型上将有一个forEach方法,但在旧版浏览器中不支持它。因此,为了能够始终如一地使用它,您必须具有支持它的环境(例如,服务器端JavaScript的Node.js),或使用Polyfill。然而,Polyfill对于这个功能是微不足道的,因为它使代码更容易阅读,所以它是一个很好的polyfill包括。[310] [311]

其它参考2


如果您使用的是 jQuery 库,则可以使用 jQuery.each :[312] [313]




$.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].
}

其它参考3


向后循环



我认为循环的 reverse 值得一提:


for (var i = array.length; i--; ) {
     // process array[i]
}


优点:




  • 您不需要在每次迭代时声明临时len变量或与array.length进行比较,其中任何一个都可能是一分钟优化。

  • 以相反的顺序从DOM中删除兄弟姐妹通常效率更高。 (浏览器需要减少内部数组中元素的移动。)

  • 如果您在循环时修改数组,则在索引 i 之后或之后(例如,您在array[i]处移除或插入项目),然后转发循环将跳过向左移动到 i 位置的项目,或者重新处理向右移动的 i 项目。在传统的for循环中,可以更新 i 以指向需要处理的下一个项目 - 1,但简单地反转迭代方向通常是更简单和更优雅的解决方案。

  • 同样,在修改或删除嵌套 DOM元素时,反向处理可以规避错误。例如,在处理子节点之前,请考虑修改父节点的innerHTML。到达子节点时,它将与DOM分离,在父内部的innerHTML被写入时已被新创建的子节点替换。

  • 键入更短读取,比其他一些可用选项更强。虽然它输给了forEach()和ES6的for ... of



缺点:




  • 以相反的顺序处理项目。如果您是从结果中构建新数组,或者在屏幕上打印内容,那么相对于原始订单,输出将会反转

  • 为了保持秩序而反复插入兄弟姐妹作为第一个子,效率低。 (浏览器将不得不改变方向。)要按顺序有效地创建DOM节点,只需循环前进并正常追加(并使用文档片段)。

  • 反向循环混淆给初级开发人员。 (根据您的观点,您可能会认为这是一个优势。)






我应该经常使用吗?



一些开发人员默认情况下使用反向循环 ,除非有充分的理由循环前进。


虽然性能提升通常微不足道,但它有点尖叫:



  只要对列表中的每个项目执行此操作,我都不关心订单!



然而,在实践中实际上是意图的可靠指示,因为它与 关心订单时的情况无法区分,并且确实 需要 以反向循环。因此实际上需要另一种构造来准确地表达不关心意图,这种意图在大多数语言中目前不可用,包括ECMAScript,但可以被称为,forEachUnordered()


如果顺序无关紧要,并且效率是一个问题(在游戏或动画引擎的最内层循环中),那么使用反向循环作为你的首选模式是可以接受的。请记住,在现有代码中看到反向循环并不一定意味着订单无关紧要!


最好使用forEach()



一般来说,对于更高级别的代码,其中清晰度和安全性是更大的问题,我建议使用Array::forEach作为默认模式:[315]



  • 很清楚阅读。

  • 表示 i 不会在块中移位(这在长forwhile循环中总是可能出现意外隐藏。)

  • 它为您提供了一个免费的闭包范围。

  • 它减少了局部变量的泄漏以及外部变量的意外碰撞(和突变)。



然后,当你在代码中看到反向for循环时,这是一个暗示它被推翻的原因很充分(可能是上述原因之一)。并且看到传统的前向循环可能表明可能发生转移。


(如果对意图的讨论对你没有意义,那么你和你的代码可能会受益于观看Crockford关于编程风格和你的大脑的讲座。)[316]





它是如何工作的?



for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse


您会注意到i--是中间子句(我们通常会看到比较),最后一个子句是空的(我们通常会看到i++)。这意味着i--也用作条件延续。至关重要的是,它会在每次迭代之前执行并检查。



  • 如何在没有爆炸的情况下从array.length开始?


    因为i--在每次迭代之前运行,所以在第一次迭代中我们实际上将访问array.length - 1处的项目,这避免了数组越界的任何问题 undefined项目。

  • 为什么它不会在索引0之前停止迭代?


    当条件i--求值为假值(当它产生0时),循环将停止迭代。


    诀窍是,与--i不同,尾随i--运算符递减i,但在递减 之前产生值 。你的控制台可以证明:


    > var i = 5; [i, i--, i];


    [5, 5, 4]


    因此,在最后一次迭代中, i 之前 1 i--表达式将其更改为 0 ,但实际上产生 1 (真相),条件通过。在下一次迭代i--将 i 更改为 -1 但产生 0 (falsey),导致执行立即退出循环的底部。


    在循环的传统前锋中,i++++i是可以互换的(正如Douglas Crockford指出的那样)。但是在反向for循环中,因为我们的减量也是我们的条件表达式,如果我们想在索引0处理项目,我们必须坚持i--






琐事



有些人喜欢在反向for循环中绘制一个小箭头,并以眨眼结束:


for (var i = array.length; i --> 0 ;) {





积分转到WYL,向我展示反向循环的好处和恐怖。

其它参考4


一些C风格的语言使用foreach来遍历枚举。在JavaScript中,这是通过for..in循环结构完成的:[317] [318]


var index,
    value;
for (index in obj) {
    value = obj[index];
}


有一个问题。 for..in将循环遍历每个对象的可枚举成员,以及其原型上的成员。为了避免读取通过对象原型继承的值,只需检查属性是否属于该对象:


for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}


另外,ECMAScript 5已经为Array.prototype添加了forEach方法,可以使用calback来枚举数组(polyfill在文档中,因此您仍然可以将它用于旧版浏览器):[[[319] [320]


arr.forEach(function (val, index, theArray) {
    //do stuff
});


值得注意的是,Array.prototype.forEach在回调返回false时不会中断。 jQuery和Underscore.js在each上提供了自己的变体,以提供可以短路的循环。[321] [322]

其它参考5


如果要循环数组,请使用标准的三部分for循环。


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


您可以通过缓存myArray.length或向后迭代来获得一些性能优化。

其它参考6


一个 forEach 实现(参见jsFiddle):[323]


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

其它参考7


如果你不介意清空阵列:


var x;

while(x = y.pop()){ 

    alert(x); //do something 

}


x将包含y的最后一个值,它将从数组中删除。您也可以使用shift()来提供和删除y中的第一项。

其它参考8


我知道这是一个老帖子,已经有很多很棒的答案了。为了更完整一点,我想我会使用AngularJS投入另一个。当然,这只适用于你使用Angular,显然,尽管如此我还是想把它放进去。[324]


angular.forEach需要2个参数和一个可选的第三个参数。第一个参数是迭代的对象(数组),第二个参数是迭代器函数,可选的第三个参数是对象上下文(在循环内部基本上称为this。


有不同的方法来使用forEach循环的角度。最简单也可能最常用的是


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


虽然,你不必这样做,你可以简单地执行以下操作,它与前面的示例相同:


angular.forEach(temp, function(item) {
    temp2.push(item);
});


现在有使用angular.forEach函数的优点和缺点,而不是内置的香草味for循环。


优点



  • 易读性

  • 易于写入

  • 如果可用,angular.forEach将使用ES5 forEach循环。现在,我将在cons部分中获得效率,因为forEach循环比for循环多慢。我之所以提到这是一个专业人士,因为保持一致和标准化是件好事。



考虑以下2个嵌套循环,这些循环完全相同。让我们说我们有2个对象数组,每个对象包含一个结果数组,每个结果都有一个Value属性,它是一个字符串(或其他)。而且,假设我们需要迭代每个结果,如果它们相等,那么执行一些操作:


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
        }
    }
}


虽然这是一个非常简单的假设示例,但是我已经使用第二种方法编写了三次嵌入for循环,而且非常难以阅读,并为此写了一篇文章。


缺点



  • 效率。 angular.forEach和本地forEach,就此而言,比正常的for循环慢得多 ......大约慢90%。因此,对于大型数据集,最好坚持本机for循环。

  • 没有休息,继续或返回支持。 continue实际上是由意外支持的,要继续angular.forEach你简单地在函数angular.forEach(array, function(item) { if (someConditionIsTrue) return; });中加入一个return;语句,这会导致它继续运行该迭代的函数。这也是因为本地forEach不支持中断或继续。



我确信还有各种其他优点和缺点,请随意添加任何你认为合适的东西。我觉得,如果你需要效率的话,最重要的是,坚持使用本地for循环来满足你的循环需求。但是,如果你的数据集较小并且可以放弃一些效率以换取可读性和可写性,那么无论如何都要在那个坏男孩中抛出angular.forEach[325] [326]

其它参考9


现在一个简单的解决方案是使用underscore.js库。它提供了许多有用的工具,例如each,如果可用的话,它会自动将作业委托给本地forEach[327]


CodePen如何工作的示例是:[328]


var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});


另见




  • 原生Array.prototype.forEach()
  • 的文档
  • 在 for_each ... in (MDN)中,解释了for each (variable in object)被弃用为ECMA-357(EAX)标准的一部分。

  • for ... of(MDN)描述了使用for (variable of object)作为Harmony(ECMAScript  6)提案的一部分进行迭代的下一种方式。


其它参考10


可能for(i = 0; i < array.length; i++)循环不是最佳选择。为什么?如果您有:[329] [330] [331] [332]


var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";


该方法将从array[0]调用array[2]。首先,这将首先引用你甚至没有的变量,第二个你不会在数组中有变量,第三个会使代码变得更大。看看这里,它是我使用的:


for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}


如果你想让它成为一个函数,你可以这样做:


function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}


如果你想打破,更多的逻辑:


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+"!!");
    }
});


它返回:


//Hello
//World
//!!!

其它参考11


jQuery中有三种foreach实现如下。[333]


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

其它参考12


自ES6开始:




list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}



原生JavaScript中没有任何for each循环。你可以使用库来获得这个功能(我推荐使用Underscore.js),在循环中使用一个简单的for[334] [335]


for (var instance in objects) {
   ...
}


但是,请注意,可能有理由使用更简单的for循环(请参阅堆栈溢出问题为什么使用for ... in与数组迭代这样一个坏主意?)


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

其它参考13


这是NON稀疏列表的迭代器,其中索引从0开始,这是处理document.getElementsByTagName或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;  


用法示例:


示例#1


var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]


示例#2


each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');


每个p标签得class="blue"


示例#3


each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);


每个其他p标签都有class="red">


示例#4


each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);


最后,前20个蓝色p标签变为绿色


使用字符串作为函数时的注意事项:该函数是在上下文中创建的,只应在您确定变量作用域的情况下使用。否则,最好传递范围更直观的函数。

其它参考14


在JavaScript中循环遍历数组有几种方法,如下所示:


for - 这是最常见的。循环代码的完整代码块




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>



forEach中没有内置的能力。要中断执行,请使用如下所示的Array#some:


[1,2,3].some(function(number) {
    return number === 1;
});


这是有效的,因为some只要以数组顺序执行的任何回调返回true,就会立即返回true,从而使其余的执行短路。
原始答案
参见某些 [338]的数组原型

其它参考15


ECMAScript5(Javascript上的版本)与Arrays一起使用。


forEach - 遍历数组中的每个项目,并为每个项目执行任何操作。


['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


万一,对使用一些内置功能的阵列操作更感兴趣。


map - 它使用回调函数的结果创建一个新数组。当您需要格式化数组的元素时,可以使用此方法。


// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']


reduce - 正如名称所说,它通过调用传入currenct元素的给定函数和先前执行的结果将数组减少为单个值。


[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


每次 - 如果数组中的所有元素都在回调函数中通过测试,则返回true或false。


// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];  
ages.every(function(elem) {  
  return elem >= 18;
});

// Output: false


过滤器 - 非常类似于除过滤器之外的每个过滤器返回一个数组,其中的元素返回true给定的函数。


// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]


希望这会有用。

其它参考16


我还想将此作为反向循环的组合添加到上面,并为那些想要这种语法的人添加答案。


var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}


优点:


这样做的好处是:你已经在第一个中获得了引用,因为它不需要稍后用另一行声明。当通过对象数组循环时它很方便。


缺点:


只要引用为false,这将会中断 - falsey(未定义等)。它可以作为一个优势使用。但是,它会使它更难阅读。而且,根据浏览器,它可以不优化,以比原始工作更快。

其它参考17


使用$.map的jQuery方式:


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

其它参考18


最接近你想法的方法是使用Array.forEach()接受将为数组的每个元素执行的clojure函数。


myArray.forEach(
  (item) => {
    // do something 
    console.log(item);
  }
);


另一种可行的方法是使用Array.map()以相同的方式工作,但mutates每个元素并返回如下:


var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

其它参考19


lambda语法通常不适用于IE 10或更低版本。


我经常使用


[].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);
});

其它参考20


var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
    console.log("Index" + index);
    console.log("Element" + item);
})

其它参考21


如果你想使用forEach(),它看起来像 -


theArray.forEach ( element => { console.log(element); });


如果你想使用for(),它看起来像 -


for(let idx = 0; idx < theArray.length; idx++){ let element = theArray[idx]; console.log(element); }