Thursday, April 23rd, 2009
How many ways can you iterate over an array in JavaScript?
Myk is one of the nicest chaps that I have had the pleasure to sit closely to in Mozilla building “S”.
He has a nice little tip on the many syntaxes that you can use to iterate over arrays in various JavaScript implementations and standards. Some folks had some interesting points on the various approaches:
for each (var item in [1, 2, 3]) alert(item);The MDC docs for “for each” say not to iterate arrays that way, too, so I never use it on them. The usual (would need to guard with
hasOwnProperty()
issue).JavaScript 1.6 added the Array.forEach method:
[1, 2, 3].forEach(function(item) { alert(item) });JavaScript 1.7 added array comprehensions for array initialization:
var squares = [item * item for each (item in [1, 2, 3])];I just realized I can (ab)use comprehensions to iterate arrays with Perl-like syntax by throwing away the result:
[alert(item) for each (item in [1, 2, 3])];I can iterate object properties the same way:
var obj = { foo: 1, bar: 2, baz: 3 }; [alert(name + "=" + obj[name]) for (name in obj)];Edward Lee points out how to use Iterators:
[alert(key + "=" + val) for ([key, val] in Iterator({a:1,b:2,c:3}))]





It’s worth noting the `for each`, comprehensions, and Iterators are not in any standard
Why would one want to do a simple operation like iterating a collection in such a cryptic way ?
Array comprehension looks like maintenance hell.
The main question is, what is the fastest method.
Some benchmarks please.
I just made a *really* ugly test case at http://nerget.com/jstests/performance/array-iteration.html to test them. In short: avoid ‘for(.. in ..)’ like the plague, but we already knew that :D
The idiom “for ( .. in .. )” is worth considering if the density of the array is very low as it only iterates over the values that have been defined. How you track the density of an array is another matter entirely.
Don’t forget JScripts Enumerator object:
var e = new Enumerator(Collection);
for (;!e.atEnd();e.moveNext()){
var x = e.item();
…
}
FirbyBoy: oh yeah, i know that (also object property iteration) i only really included it for the sake of reference.
@ywg: Array comprehensions are a lot easier to read than the current forEach() method where you have to supply a function which makes it fairly long. They might look cryptic at first sight, but that’s because you aren’t used to them.
Yeah, great! :) I didn’t know that with JavaScript 1.7 list comprehensions (and generators) were introduced. When I got serious with JavaScript I already have had a strong Python background and therefore really missed syntactical sugar like this.
Yeah, the best choice depends on sparseness. In C, I almost never had arrays as sparse as ones I’d use today in JS. Say I set arr[0] to “tiny” and arr[10000] to “big”. How big is the array? Two elements or 10001 elements? First time I ever read about sparse arrays was in reading about how the old spreadsheets were programmed (maybe a discussion of Visicalc in Byte magazine). It seemed so esoteric at the time, but it’s something that just falls out of JavaScript’s design. Most of the knocks I’ve heard against JS on the array side is how slow it is with dense traditional arrays (treating arrays just like objects), but I think some of the new engines have really sped all this up.
@olliej
Here are a few more that are a lot quicker
nopIteration0 : 22ms
function nopIteration0(a, f) {
var start = new Date;
var i = a.length;
while(i--) {
}
var end = new Date;
return end - start;
}
nopIteration1 : 38ms
function nopIteration1(a, f) {
var start = new Date;
var l = a.length;
for (var i = 0; i < l; i++){
}
var end = new Date;
return end - start;
}
What about Array.forEach? No not Array.prototype.forEach, it differs because it can handle array-like objects such as nodelists and arguments
Array.forEach(arguments, function(){
//do something
}, scope)
I find it the most useful method for array iterations.
@gmariani: added those to the test now. I had deliberately chosen not to cache the length property, although i honestly cannot recall why :D
@RyanMorr: Actually Array.prototype.forEach (and most other array prototype functions) are defined as being generic, the mozilla MDC documentation gives JS implementations as well and there’s no type checking, basically they’re all
var l = this.length;
for(i = 0;i i<l; i++) { … }
I typically use the for loop
var length = arr.length
for(var i=0;i<length;i++){
// code here
}
Based off olliej’s test, its one of the faster ones. I was certainly surprised to see that recalculating the arr length through each iteration was so costly, but it makes sense in that it adds at best a constant or at worst a linear operation to an already linear process.
You really only need to worry about loop performance if you are dealing with large arrays though, which most javascript applications I develop don’t use.
If the .length is done the same way as in java, then it is no optimisation to copy it first in another variable. its just a public attribute of the array (object). If you use things like .length() or .size() then you should do that, because these are method calls and eat time.
Correct me if I am wrong.
JavaScript’s for-loop construct allows you to declare multiple loop-local variables, which is useful for memoizing array length without leaking variables into the outer scope.
var a = [ 1, 2, 3 ];
for (var i = 0, len = a.length; i < len; i++) {
// work
}
Also, though I haven’t benchmarked it, when order of traversal isn’t important, I typically prefer fewer locals and opt instead of constant comparison.
for (var i = a.length - 1; i >= 0; i--) {
// work
}
@duncanbeevers: Javascript doesn’t have block scope. Those aren’t “loop-local” variables, which is why using c-style loops kinda sucks in Javascript.
For instance, guess what this displays:
var i = 50;
for( var i = 0; i< 10; i++ ) {}
alert(i);
Every time you use a for loop and define a loop variable, that variable is scoped to the containing function, not the loop block.
I miss perl-style map and foreach every time I write a loop in Javascript.
Patrick
Like some of you I heard this is the right way
var browsers = new Array(‘opera’,’safari’,’firefox’,’…’);
for (var index = 0, len = browsers.length; index < len; ++index) alert(browsers[index]);
But know i see that it seem most logical, no ?
browsers.forEach(function(item) { alert(item); });