Thursday, April 23rd, 2009

How many ways can you iterate over an array in JavaScript?

Category: JavaScript, Tip

<>p>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 in:

javascript
< view plain text >
  1. 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:

javascript
< view plain text >
  1. [1, 2, 3].forEach(function(item) { alert(item) });

JavaScript 1.7 added array comprehensions for array initialization:

javascript
< view plain text >
  1. 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:

javascript
< view plain text >
  1. [alert(item) for each (item in [1, 2, 3])];

I can iterate object properties the same way:

javascript
< view plain text >
  1. var obj = { foo: 1, bar: 2, baz: 3 };
  2. [alert(name + "=" + obj[name]) for (name in obj)];

Edward Lee points out how to use Iterators:

javascript
< view plain text >
  1. [alert(key + "=" + val) for ([key, val] in Iterator({a:1,b:2,c:3}))]

Related Content:

Posted by Dion Almaer at 4:29 am
18 Comments

+++--
3.5 rating from 44 votes

18 Comments »

Comments feed TrackBack URI

It’s worth noting the `for each`, comprehensions, and Iterators are not in any standard

Comment by olliej — April 23, 2009

Why would one want to do a simple operation like iterating a collection in such a cryptic way ?
Array comprehension looks like maintenance hell.

Comment by ywg — April 23, 2009

The main question is, what is the fastest method.

Some benchmarks please.

Comment by Aimos — April 23, 2009

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

Comment by olliej — April 23, 2009

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.

Comment by FirbyBoy — April 23, 2009

Don’t forget JScripts Enumerator object:

var e = new Enumerator(Collection);
for (;!e.atEnd();e.moveNext()){
var x = e.item();

}

Comment by TNO — April 23, 2009

FirbyBoy: oh yeah, i know that (also object property iteration) i only really included it for the sake of reference.

Comment by olliej — April 23, 2009

@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.

Comment by nene — April 23, 2009

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.

Comment by geilp — April 23, 2009

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.

Comment by Nosredna — April 23, 2009

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

Comment by gmariani — April 23, 2009

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.

Comment by RyanMorr — April 23, 2009

@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++) { … }

Comment by olliej — April 23, 2009

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.

Comment by cnizz — April 23, 2009

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.

Comment by Aimos — April 24, 2009

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
}

Comment by duncanbeevers — April 24, 2009

@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

Comment by patspam — April 24, 2009

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

Comment by molokoloco — April 26, 2009

Leave a comment

You must be logged in to post a comment.