For-each在JavaScript中的数组?

Dante1986 4081 javascript arrays iteration foreach loops

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

我以为它是这样的:

forEach(instance in theArray)

theArray我的阵列在哪里,但这似乎是不正确的.

T.J. Crowder.. 6346

TL; DR

  • for-in除非您使用保护措施或至少知道它为什么会咬你,否则不要使用.
  • 通常你最好的赌注

    • 一个for-of环(ES2015 +只),
    • Array#forEach(spec| MDN)(或其亲属some等)(仅限ES5 +),
    • 一个简单的老式for循环,
    • for-in有保障措施.

但是,还有很多更多的探索,阅读...


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

我会很快注意到,您可以使用ES2015选项现在,即使是在ES5引擎,通过transpiling ES2015到ES5.搜索"ES2015 transpiling"/"ES6 transpiling"了解更多...

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

对于实际阵列

ECMAScript 5("ES5")中有三个选项,目前支持最广泛的版本,以及ECMAScript 2015中添加的两个选项("ES2015","ES6"):

  1. 使用forEach和相关(ES5 +)
  2. 使用简单的for循环
  3. 使用for-in 正确
  4. 使用for-of(隐式使用迭代器)(ES2015 +)
  5. 明确使用迭代器(ES2015 +)

细节:

1.使用forEach和相关

在任何模糊的现代环境(因此,不是IE8)中,您可以访问ArrayES5添加的功能(直接或使用polyfill),您可以使用forEach(spec| MDN):

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

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

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

forEach 有一个好处是你不必在包含作用域中声明索引和值变量,因为它们作为参数提供给迭代函数,因此很好地限定了只是那个迭代.

如果您担心为每个数组条目调用函数的运行时成本,请不要这样做; 细节.

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

  • every(第一次回调返回时停止循环false或出现错误)
  • some(第一次回调返回时停止循环true或者某些事情)
  • filter(创建一个新数组,包括过滤函数返回的元素,true并省略返回的元素false)
  • map (根据回调返回的值创建一个新数组)
  • reduce (通过重复调用回调来构建一个值,传入以前的值;查看详细信息的规范;对于汇总数组的内容和许多其他内容很有用)
  • reduceRight(比如reduce,但是按降序而不是按升序排列)

2.使用简单的for循环

有时旧的方式是最好的:

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

如果数组的长度将不会在循环过程中改变,它在性能敏感的代码(不可能),一个稍微复杂一点的版本抓住了长度达阵可能是一个很小的有点快:

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"

And when you do that, not just value but also index is recreated for each loop iteration, meaning closures created in the loop body keep a reference to the index (and value) created for that specific iteration:

let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        alert("Index is: " + index);
    });
}

If you had five divs, you'd get "Index is: 0" if you clicked the first and "Index is: 4" if you clicked the last. This does not work if you use var instead of let.

3. Use for-in correctly

You'll get people telling you to use for-in, but that's not what for-in is for. for-in loops through the enumerable properties of an object, not the indexes of an array. The order is not guaranteed, not even in ES2015 (ES6). ES2015 does define an order to object properties (via [[OwnPropertyKeys]], [[Enumerate]], and things that use them like Object.getOwnPropertyKeys), but it does not define that for-in will follow that order. (Details in this other answer.)

Still, it can be useful, particularly for sparse arrays, if you use appropriate safeguards:

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

Note the two checks:

  1. That the object has its own property by that name (not one it inherits from its prototype), and

  2. That the key is a base-10 numeric string in its normal string form and its value is <= 2^32 - 2 (which is 4,294,967,294). Where does that number come from? It's part of the definition of an array index in the specification. Other numbers (non-integers, negative numbers, numbers greater than 2^32 - 2) are not array indexes. The reason it's 2^32 - 2 is that that makes the greatest index value one lower than 2^32 - 1, which is the maximum value an array's length can have. (E.g., an array's length fits in a 32-bit unsigned integer.) (Props to RobG for pointing out in a comment on my blog post that my previous test wasn't quite right.)

That's a tiny bit of added overhead per loop iteration on most arrays, but if you have a sparse array, it can be a more efficient way to loop because it only loops for entries that actually exist. E.g., for the array above, we loop a total of three times (for keys "0", "10", and "10000" — remember, they're strings), not 10,001 times.

Now, you won't want to write that every time, so you might put this in your toolkit:

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}

And then we'd use it like this:

for (key in a) {
    if (arrayHasOwnIndex(a, key)) {
        console.log(a[key]);
    }
}

Or if you're interested in just a "good enough for most cases" test, you could use this, but while it's close, it's not quite correct:

for (key in a) {
    // "Good enough" for most cases
    if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
        console.log(a[key]);
    }
}

4. Use for-of (use an iterator implicitly) (ES2015+)

ES2015 adds iterators to JavaScript. The easiest way to use iterators is the new for-of statement. It looks like this:

var val;
var a = ["a", "b", "c"];
for (val of a) {
    console.log(val);
}

Output:

a
b
c

Under the covers, that gets an iterator from the array and loops through it, getting the values from it. This doesn't have the issue that using for-in has, because it uses an iterator defined by the object (the array), and arrays define that their iterators iterate through their entries (not their properties). Unlike for-in in ES5, the order in which the entries are visited is the numeric order of their indexes.

5. Use an iterator explicitly (ES2015+)

Sometimes, you might want to use an iterator explicitly. You can do that, too, although it's a lot clunkier than for-of. It looks like this:

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

The iterator is an object matching the Iterator definition in the specification. Its next method returns a new result object each time you call it. The result object has a property, done, telling us whether it's done, and a property value with the value for that iteration. (done is optional if it would be false, value is optional if it would be undefined.)

The meaning of value varies depending on the iterator; arrays support (at least) three functions that return iterators:

  • values(): This is the one I used above. It returns an iterator where each value is the array entry for that iteration ("a", "b", and "c" in the example earlier).
  • keys(): Returns an iterator where each value is the key for that iteration (so for our a above, that would be "0", then "1", then "2").
  • entries(): Returns an iterator where each value is an array in the form [key, value] for that iteration.

For Array-Like Objects

Aside from true arrays, there are also array-like objects that have a length property and properties with numeric names: NodeList instances, the arguments object, etc. How do we loop through their contents?

Use any of the options above for arrays

At least some, and possibly most or even all, of the array approaches above frequently apply equally well to array-like objects:

  1. Use forEach and related (ES5+)

    The various functions on Array.prototype are "intentionally generic" and can usually be used on array-like objects via Function#call or Function#apply. (See the Caveat for host-provided objects at the end of this answer, but it's a rare issue.)

    Suppose you wanted to use forEach on a Node's childNodes property. You'd do this:

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

    If you're going to do that a lot, you might want to grab a copy of the function reference into a variable for reuse, e.g.:

    // (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. Use a simple for loop

    Obviously, a simple for loop applies to array-like objects.

  3. Use for-in correctly

    for-in with the same safeguards as with an array should work with array-like objects as well; the caveat for host-provided objects on #1 above may apply.

  4. Use for-of (use an iterator implicitly) (ES2015+)

    for-of will use the iterator provided by the object (if any); we'll have to see how this plays with the various array-like objects, particularly host-provided ones. For instance, the specification for the NodeList from querySelectorAll was updated to support iteration. The spec for the HTMLCollection from getElementsByTagName was not.

  5. Use an iterator explicitly (ES2015+)

    See #4, we'll have to see how iterators play out.

Create a true array

Other times, you may want to convert an array-like object into a true array. Doing that is surprisingly easy:

  1. Use the slice method of arrays

    We can use the slice method of arrays, which like the other methods mentioned above is "intentionally generic" and so can be used with array-like objects, like this:

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

    So for instance, if we want to convert a NodeList into a true array, we could do this:

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

    See the Caveat for host-provided objects below. In particular, note that this will fail in IE8 and earlier, which don't let you use host-provided objects as this like that.

  2. Use spread syntax (...)

    It's also possible to use ES2015's spread syntax with JavaScript engines that support this feature:

    var trueArray = [...iterableObject];
    

    So for instance, if we want to convert a NodeList into a true array, with spread syntax this becomes quite succinct:

    var divs = [...document.querySelectorAll("div")];
    
  3. Use Array.from (spec) | (MDN)

    Array.from (ES2015+, but easily polyfilled) creates an array from an array-like object, optionally passing the entries through a mapping function first. So:

    var divs = Array.from(document.querySelectorAll("div"));
    

    Or if you wanted to get an array of the tag names of the elements with a given class, you'd use the mapping function:

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

Caveat for host-provided objects

If you use Array.prototype functions with host-provided array-like objects (DOM lists and other things provided by the browser rather than the JavaScript engine), you need to be sure to test in your target environments to make sure the host-provided object behaves properly. Most do behave properly (now), but it's important to test. The reason is that most of the Array.prototype methods you're likely to want to use rely on the host-provided object giving an honest answer to the abstract [[HasProperty]] operation. As of this writing, browsers do a very good job of this, but the 5.1 spec did allow for the possibility a host-provided object may not be honest. It's in §8.6.2, several paragraphs below the big table near the beginning of that section), where it says:

Host objects may implement these internal methods in any manner unless specified otherwise; for example, one possibility is that [[Get]] and [[Put]] for a particular host object indeed fetch and store property values but [[HasProperty]] always generates false.

(I couldn't find the equivalent verbiage in the ES2015 spec, but it's bound to still be the case.) Again, as of this writing the common host-provided array-like objects in modern browsers [NodeList instances, for instance] do handle [[HasProperty]] correctly, but it's important to test.)

  • @Pius:如果你想打破循环,你可以使用[`some`](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.17).(我本来希望允许打破'forEach`,但他们,嗯,没有问我.;-)) (69认同)
  • 我还想补充一点,`.forEach`无法有效破解.你必须抛出异常来执行休息. (36认同)
  • @TJCrowder是的,即使它看起来更像是一种解决方法,因为它不是它的主要目的. (5认同)
  • @ user889030:你需要一个`,`在`k = 0`之后,而不是`;`.记住,编程是很多东西,其中一个是密切关注细节... :-) (5认同)
  • @JimB:上面已经介绍了(并且`length`不是方法).:-) (4认同)

PatrikAkerst.. 473

编辑:这个答案绝对是过时的.要获得更现代的方法,请查看阵列上可用的方法.感兴趣的方法可能是:

  • 的forEach
  • 地图
  • 过滤
  • 压缩
  • 降低
  • 一切
  • 一些

JavaScript中迭代数组的标准方法是vanilla for-loop:

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

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

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

  • 您可以使用内联长度缓存:for(var i = 0,l = arr.length; i <l; i ++) (20认同)
  • @ wardha-Web这是故意的.它使我们能够使用单个`var`-keyword声明多个变量.如果我们使用了分号,那么`element`就会在全局范围内声明(或者说,JSHint在它到达生产之前会尖叫我们). (5认同)
  • 逗号在第一行末尾是故意的,还是拼写错误(可以是分号)? (2认同)

用户甲.. 214

如果您正在使用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].
}

  • 只是为了它:jQuery每个都比原生解决方案慢得多.jQuery建议在可能的情况下使用本机JavaScript而不是jQuery.http://jsperf.com/browser-diet-jquery-each-vs-for-loop (43认同)
  • 有点让我想起这个:http://i.stack.imgur.com/ssRUr.gif (21认同)
  • 当你可以使用vanilla js时,不要使用jQuery (7认同)

joeytwiddle.. 94

向后循环

我认为反向循环值得一提:

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

好处:

  • 您不需要声明临时len变量,也不需要array.length在每次迭代时进行比较,其中任何一个都可能是一分钟优化.
  • 以相反的顺序从DOM中删除兄弟姐妹通常更有效.(浏览器需要减少内部数组中元素的移动.)
  • 如果在循环时,在索引i处或之后修改数组(例如,删除或插入项目),则前向循环将跳过向左移动到位置i的项目,或者重新处理第i个项目向右转.在传统的for循环中,您可以更新i以指向需要处理的下一个项目 - 1,但简单地反转迭代方向通常是一种更简单,更优雅的解决方案.array[i]
  • 类似地,在修改或删除嵌套的 DOM元素时,反向处理可以避免错误.例如,在处理子节点之前,请考虑修改父节点的innerHTML.到达子节点时,它将与DOM分离,在写入父内部HTML时,已被新创建的子节点替换.
  • 这是更短的录入,读取,比一些可用的其他选项.虽然它失去了forEach()和ES6的for ... of.

缺点:

  • 它以相反的顺序处理项目.如果您从结果中构建新数组,或在屏幕上打印内容,则输出将相对于原始顺序反转.
  • 为了保留他们的顺序,反复插入兄弟姐妹作为第一个孩子的DOM 效率较低.(浏览器将不得不改变方向.)要按顺序有效地创建DOM节点,只需循环前进并正常追加(并使用"文档片段").
  • 反向循环让初级开发人员感到困惑.(您可能会认为这是一个优势,具体取决于您的前景.)

我应该经常使用它吗?

一些开发人员默认使用reverse for循环,除非有充分的理由向前循环.

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

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

然而在实践中是不是真正意图的可靠指标,因为它是从这些场合没有区别,当你关心秩序,确实需要循环反向.因此实际上需要另一种构造来准确地表达"不关心"的意图,这种意图目前在大多数语言中都不可用,包括ECMAScript,但是可以被称为例如forEachUnordered().

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

最好使用forEach()

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

  • 很清楚阅读.
  • 它表明不会在块中移位(这总是可能会隐藏在long forwhile循环中.)
  • 它为您提供了一个免费的闭包范围.
  • 它减少了局部变量的泄漏以及外部变量的意外碰撞(和突变).

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

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


它是如何工作的?

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

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

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

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

    因为每次迭代之前i--运行,所以在第一次迭代时我们实际上将访问该项目,避免了Array-out-of-bounds项目的任何问题.array.length - 1 undefined

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

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

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

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

    [5, 5, 4]

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

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


琐事

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

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

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

  • 我忘了添加**[基准](http://jsperf.com/loops/33)**.我也忘了提到反向循环是如何在像6502这样的8位处理器上进行重大优化,你真的可以免费获得比较! (2认同)
  • 这对于反向循环怎么样?var i = array.length; 当我 - ) { ... (2认同)

zzzzBov.. 75

一些C风格的语言用于foreach循环枚举.在JavaScript中,这是通过for..in循环结构完成的:

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

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

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

另外,ECMAScript 5添加了一个forEach方法Array.prototype,可以使用calback对数组进行枚举(polyfill在文档中,因此您仍然可以将它用于旧版浏览器):

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

重要的是要注意,Array.prototype.forEach当回调返回时不会中断false.jQueryUnderscore.js提供了自己的变体,each以提供可以短路的循环.

  • @CiaranG,在JavaScript中,通常会看到`each`方法允许`return false`用于打破循环,但是使用`forEach`这不是一个选项.可以使用外部标志(即`if(flag)return;`,但它只会阻止函数体的其余部分执行,'forEach`仍然会继续迭代整个集合. (4认同)
  • 那么如何突破一个ECMAScript5 foreach循环,就像我们对普通的for循环或像C风格语言中发现的foreach循环一样? (2认同)

Quentin.. 34

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

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

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

  • for(var i = 0,length = myArray.length; i <length; i ++)应该这样做 (5认同)
  • @EdsonMedina我道歉,我完全错了.在作业之后使用`,`确实*不*引入新的全局,所以你的建议只是**很好**!我在混淆这个问题时遇到了另一个问题:在赋值[确实创建](http://stackoverflow.com/questions/1758576/multiple-left-hand-assignment-with-javascript#1758912)之后使用`=` . (5认同)
  • @EdsonMedina这也将创建一个名为`length`的新全局变量.;) (4认同)
  • @joeytwiddle是的,但这超出了这篇文章的范围.无论如何,你将创建一个全局变量. (3认同)

用户甲.. 28

我知道这是一个老帖子,已经有很多很棒的答案了.为了更完整一点,我想我会使用AngularJS投入另一个.当然,这只适用于你使用Angular的情况,显然,无论如何我仍然愿意.

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循环.现在,我将获得的利弊部分efficientcy,作为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
        }
    }
}

诚然,这是一个非常简单的假设的例子,但我已经写了三重嵌入使用第二种方法循环,这是非常难读,写为这一问题.

缺点

  • 效率.angular.forEach和原生forEach,对于这个问题,都这么多比正常情况下慢for循环....大约慢90% .因此对于大型数据集,最好坚持原生for循环.
  • 没有休息,继续或返回支持.continue实际上是由" 意外 " 支持,继续在angular.forEach你简单地return;在函数中放置一个语句,angular.forEach(array, function(item) { if (someConditionIsTrue) return; });这将导致它继续执行该迭代的函数.这也是由于本机forEach不支持中断或继续.

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


gaby de wild.. 27

如果你不介意清空数组:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x将包含最后一个值,y它将从数组中删除.您还可以使用shift()哪个将提供和删除第一个项目y.

  • 如果您碰巧有一个稀疏的数组,如`[1,2,undefined,3]`,它就不起作用. (3认同)

nmoliveira.. 27

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


Micka.. 24

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

CodePen如何工作的示例是:

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

也可以看看


Rajesh Paul.. 24

有三种实现方式foreach的jQuery如下.

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


Federico Pir.. 22

可能for(i = 0; i < array.length; i++)循环不是最好的选择.为什么?如果你有这个:

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
//!!!


Zaz.. 21

从ES6开始:

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

of避免了相关的怪异in,并使其喜欢的工作for任何其他语言的循环,并let结合i作为函数内相对于内环路.

{}当只有一个命令时(例如在上面的例子中),可以省略大括号().


joidegn.. 17

for each原生JavaScript中没有任何循环.您可以使用库来获得此功能(我建议使用Underscore.js),使用简单的forin循环.

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

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

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


Tim.. 17

这是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标签变为绿色

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


Alireza.. 16

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

因为 - 这是最常见的一个.用于循环的完整代码块

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>

while - 循环而条件通过.它似乎是最快的循环

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do/while - 在条件为真时循环遍历代码块,将至少运行一次

var text = ""
var i = 0;
do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);
document.getElementById("example").innerHTML = text;
<p id="example"></p>

功能循环 - ,forEach,map,filterreduce(他们通过循环功能,但如果你需要做的事情与你的阵列等使用

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

有关数组函数编程的更多信息和示例,请参阅博客文章JavaScript中函数编程:map,filter和reduce.


Priyanshu Ch.. 14

没有内置的能力进入forEach.要中断执行,请使用Array#some以下内容:

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

这是有效的,因为some只要以数组顺序执行的任何回调返回true,就会返回true,从而使其余的执行短路. 原来的答案 见阵原型一些


Anil Kumar A.. 14

使用Arrays的ECMAScript5(Javascript版本).

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

every - 如果数组中的所有元素都在回调函数中传递测试,则返回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

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

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

// Output: [2,4,6]

希望这会有用.


Volkan Seçki.. 11

我还想将此作为一个反向循环的组合添加到上面的答案中,对于那些想要这种语法的人来说也是如此.

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

优点:

这样做的好处是:你已经在第一个中有了引用,就像以后不需要用另一行声明一样.循环通过对象数组时很方便.

缺点:

只要引用为false,这将会中断 - falsey(未定义等).它可以作为一个优势使用.但是,它会让它更难阅读.并且还取决于浏览器,它可以"不"优化,以比原始工作更快.


DanFromGerma.. 10

jQuery方式使用$.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];


Ante Jablan .. 6

最接近你的想法的方法是使用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]


用户甲.. 6

使用循环与ES6 解构扩展运算符

虽然一些javascript退伍军人可能认为它很混乱,但是小辈或其他一些人可能觉得它很有用,因此对于ES6的新手来说,解构和扩展运算符的使用已被证明是非常有用的.

以下示例将使用for...of语句和.forEach方法.

实施例6,7和8可以与像任何官能环路被使用.map,.filter,.reduce,.sort,.every,.some,有关这些方法的详细信息检查出数组对象.

示例1:正常for...of循环 - 这里没有技巧.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

示例2:将单词拆分为字符

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);

}

例3:用a key和.循环value

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type: 
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on internet explorer unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

示例4:内联获取对象属性

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

示例5:获取所需内容的深层对象属性

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

实施例6:实施例3是否与.一起使用.forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

实施例7:实施例4是否与.forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions 
// are required to be surrounded by parenthesis
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

实施例8:实施例5是否与.一起使用.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


Murtuza Husa.. 5

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

我经常使用

[].forEach.call(arrayName,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);
});


提问时间:

查看次数:

3583831 次

最近活跃:

7 月,2 周 前