For var index in vs. forEach
In javascript, if I want to iterate over every element in an array, I have several ways to do it:
1.
for(var i =0; i<array.length; i++){}
2.
array.forEach(function(item, index){});
3.
for (var index in array){}
The first is generic, but if I'm feeling lazy, I want to use the second or third.
But I'm wondering if there is a difference between the two and in which situation should I choose which one?
source to share
These are all subtly different approaches.
for(var i = 0; i<array.length; i++){}
is a proven method; feels like C, works like C.
- Iterations over every index of the array, even those that don't have a corresponding property / element.
- Works with any object that supports
.length
and properties named [0..length); while it also works in sparsely populated areas, additional protection may be required. - In contrast
forEach
, this allows for usecontinue/break/return
as well as manual adjustment of the index from within the loop body, if ever required.
array.forEach(function(item, index){})
is the approach I prefer because it is often enough, it feels cleaner and "lazy" .
- Iterates through all the values / array index that have the property.
- A new scope function is implicitly implied for each loop.
- As long as it is defined in Array.prototype, it can be used mostly on array-like objects with
call/apply
. - It has more overhead than it does
for..i++
(link stolen from James G.'s comment). However, this often does not matter, and the relative difference in performance will decrease as the work done in the body increases.
for (var index in array){}
should not be used when working with array / sequence iteration.
- Iterate over all non-enumerated properties, walk through [prototype], and
- Property names are repeated in implementation order 2
Here's a demo of some of the differences :
var array = [];
array[0] = 1;
array[2] = 2; // Note that `1 in array` is false as it was never set
array.hello_world = 3;
var a = 0;
for(var i = 0; i<array.length; i++){
a += array[i]
}
// -> NaN; because array[1] was undefined
console.log("index: " + a);
var b = 0;
array.forEach(function (v, i) {
b += v;
});
// -> 3; because v was never undefined (as array[1] was skipped)
console.log("forEach: " + b);
var c = 0;
for (var p in array) {
c += array[p];
}
// -> 6; picked up "hello_world" but didn't pick up missing "1" property
console.log("for..in: " + c);
2 An example of creating a different order of iterations between browsers :
var a = [];
for (var i = 100000; i > 0; i -= 1000) { a[i] = i; }
var s = "";
for (var p in a) { s += p + ","; }
console.log(s);
Chrome and IE 10 repeat ascending; FF iterates to insert (for smaller ranges, FireFox also sorts in ascending order). Just don't use this approach to repeat a sequence and there won't be such problems.
source to share
The third one is a bad idea because it iterates over objects, not elements in the array (although you might mistake this for this, since the elements are properties (but there may be other properties)).
Here's another other question: Looping through an array in JavaScript
And helpful off-site discussion: http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/
And from Crockford: http://javascript.crockford.com/code.html#for%20statement
source to share
- Will only work for arrays. You cannot traverse objects this way.
- Will only work for arrays. Slower than # 1, but by creating a new scope
function
, you ensure that any asynchronous callbacks that contain your parametersindex
oritem
grab the current value as they go through the scope, not their final value. - Great for walking over objects as well as arrays. Slightly slower than # 1 when working with arrays. This can be dangerous because some naughty libraries like PrototypeJS add properties to the Array prototype, which means you end up with indices that don't actually represent the elements in the array. Don't use this if there is a chance your code will be used on the same page as the library that does it.
Another interesting difference occurs when your array contains "undefined" values. This is unusual in my experience, but it will make a difference. For example:
var array = [0, undefined, 2, 3];
array[2] = undefined;
delete array[3];
array[5] = 5;
Approach # 1 shows indices 0, 1, 2, 3, 4, 5 showing undefined values on 1, 2, 3 and 4.
Approaches # 2 and # 3 to index 0, 1, 2, 5 showing undefined values at values 1 and 2.
source to share