54

In JavaScript I can have an array with holes:

a = [];
a[0] = 100;
a[5] = 200;
a[3] = 300;

a.forEach(function(x) {alert(x);});

I could not find information about whether elements would be processed in ascending order or this is not reliable fact.

I checked that "for .. in" loop traverses array indices in ascending order, while property names of an object are traversed in the same order they were added to object (at least it looks so).

(I.e. it looks like arrays are internally trees of some kind and objects are hashtables.)

I just found that Rhino JavaScript traverses non-existent elements also: http://ideone.com/7Z3AFh (unlike for..in).

double-beep
  • 5,031
  • 17
  • 33
  • 41
Rodion Gorkovenko
  • 2,670
  • 3
  • 24
  • 37

3 Answers3

83

The ECMA-262, 5th edition specification and MDN's Array.forEach() page both show the algorithm for .forEach(), and it will definitely iterate over array elements in ascending index order (skipping indices that were never assigned a value).

Of course, some browsers may not implement that algorithm properly, but I'm not aware of any that don't.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • Hm. I read it several times before and only now see that I was inattentive. thanks. This method does not traverse internal structure at all, as I see... :( – Rodion Gorkovenko Nov 28 '12 at 08:58
16

The specification says forEach will visit the array elements in numeric order. It doesn't visit elements that don't exist. See the link for details. So for your example array, it will visit element 0, then 3, then 5. The order in which you add them to the array has no effect on the order in which they're visited.

I checked that "for .. in" loop traverses array indices in ascending order, while property names of an object are traversed in the same order they were added to object (at least it looks so).

The order in which for-in visits object properties is not defined by the specification, not even in ES2015 (aka ES6), despite the fact that ES2015 defines an order for object properties — that order doesn't apply to for-in or Object.keys. (More about that in this answer.) If you want to visit properties in the order defined in ES2015, you can use Object.getOwnPropertyNames (for properties that aren't defined with Symbol names) or Reflect.ownKeys (for both Symbol and string property names [remember numeric property names are really strings]). Both of those do respect property order.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Chrome now sorts in numerical order when doing `Object.getOwnPropertyNames` and `Reflect.ownKeys`. The only way I could find to *not* sort them was to make them all non-numeric strings by prepending a `_` to the beginning of the keys. – Mike Aug 02 '16 at 06:49
  • @Mike: Yeah. Doing the spec, they made a point of *not* requiring vendors to backfit that order on `for-in` and `Object.keys`, I think in case vendors had a good reason to keep their current ordering for a few versions. But I think in practice vendors have been happy to just be consistent and move forward with that consistency. – T.J. Crowder Aug 02 '16 at 07:08
5

Straight out of the ECMAScript standard

forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.

So Array.forEach will skip certain elements in an array. Your example

a.forEach( function( value ) { console.log( value ) }); // prints 100, 300, 200

If you do want to traverse the array in ascending order and all your elements are numbers then you can sort the array beforehand like so

a.sort( function( a, b ) { return a - b });
// this now prints 100, 200, 300
a.forEach( function( value ) { console.log( value ) }); 
Bruno
  • 5,772
  • 1
  • 26
  • 43