For-in Revisited

A while back I was discussing the differences between VBScript’s For-Each and JScript’s for-in loops.

A coworker asked me today whether there was any way to control the order in which the for-in loop enumerates the properties. They wanted to get the list in alphabetical order for some reason.

Unfortunately, we don’t support that. The specification says (ECMA 262 Revision 3 section 12.6.4):

The mechanics of enumerating the properties is implementation dependent. The order of enumeration is defined by the object. Properties of the object being enumerated may be deleted during enumeration. If a property that has not yet been visited during enumeration is deleted, then it will not be visited. If new properties are added to the object being enumerated during enumeration, the newly added properties are not guaranteed to be visited in the active enumeration.

Enumerating the properties of an object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not enumerated if it is “shadowed” because some previous object in the prototype chain has a property with the same name.

Our implementation enumerates the properties in the order that they were added. This also implies that properties added during the enumeration will be enumerated.

If you want to sort the keys then you’ll have to do it the hard way — which, fortunately, is not that hard. Enumerate them in by-added order, add each to an array, and sort that array.

var myTable = new Object(); 
myTable["blah"] = 123; 
myTable ["abc"] = 456 
myTable [1234] = 789; 
myTable ["def"] = 346; 
myTable [345] = 566; 
var keyList = new Array(); 
for(var prop in myTable) 
for(var index = 0 ; index < keyList.length ; ++index)
      print(keyList[index] + " : " + myTable[keyList[index]]); 

This has the perhaps unfortunate property that it sorts numbers in alphabetical, not numeric order. If that bothers you, then you can always pass a comparator to the sort method that sorts numbers however you’d like.

Commentary from 2019:

A reader asked whether it was “tedious” to solve the problem that I mentioned in the final paragraph: that numbers are sorted as though they were strings, not numbers. It’s not too hard. The comparison will get strings; see if the operands parse as strings, and if so, come up with some rule. Say, any number is smaller than any non-number, numbers compare as numbers, and non-numbers compare as strings.

This is another example of API design decisions that have a negative impact on developers who have reasonable needs. Every platform should come with a “smart sort” algorithm that knows how to deal with strings that have numbers in them. It’s a slightly tricky algorithm, so let’s have experts write it once, test it heavily, and then line-of-business developers don’t need to try to re-invent it.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s