Guaranteeing enumeration order in for-in loops (AS3) +
Somebody asked: "Why don't the properties of an object in a for-in loop get enumerated in the same order as they were set?" (AS3)
Well, that's just the way it is.
The enumeration order is not guaranteed due to the way dynamic properties are stored internally.
var obj:Object = {};
obj.name = "Manish Jethani";
obj.city = "Copenhagen";
obj.os = "Mac OS X 10.4";
for (var p:* in obj)
trace(p + ": " + obj[p]);
The above can print name, city, and os in any order. This is well documented.
If you wish to preserve the order in a for-in or for-each-in loop, you'll have to do some additional book-keeping for the object. The best way to do this is to create your own custom type that does enumerations in the preferred order.
Let's call our type OrderedObject. It will be based on Flash's Proxy class.
dynamic public class OrderedObject extends Proxy
{
private var content:Object = {};
private var contentByIndex:Array = [];
override flash_proxy function nextName(index:int):String
{
return contentByIndex[index - 1];
}
override flash_proxy function nextNameIndex(index:int):int
{
if (index < contentByIndex.length)
return index + 1;
else
return 0;
}
override flash_proxy function setProperty(name:*, value:*):void
{
content[name] = value;
for each (var p:* in contentByIndex) {
if (p == name)
// If the property already exists, don't change the order.
return;
}
contentByIndex.push(name);
}
...
}
(For simplicity sake, I've left out the implementations of the deleteProperty, getProperty, hasProperty, and nextValue methods.)
What are we doing here?
In setProperty, we store the property name in the contentByIndex array. Afterwards, when a for-in loop is run over the object, nextNameIndex and nextName are called, in which we return the property names in the same order as they were set, by retrieving them one by one from the contentByIndex array.
var obj:Object = new OrderedObject();
obj.name = "Manish Jethani";
obj.city = "Copenhagen";
obj.os = "Mac OS X 10.4";
for (var p:* in obj)
trace(p + ": " + obj[p]);
Now the order is guaranteed! name, city, os.
It's going to make sense when you run it. The full source for the OrderedObject class is available on my code site: OrderedObject.as.
I came across this post that was very similar to something I was working for my framework. I just wanted to share some tweaks to your code example:
I basically modified your for loops when setting/deleting properties to use
indexOf to help speed up the calls. Its a minor change but one that will
really make a difference when dealing with large lists of properties.
here are two examples:
For setting a property.
For deleting a property.
I also added a merged function:
I figured why not add the ability to combine OrderedObjects together on the
fly. The only problem with this merge function is that it doesn't do a clean copy of another objects properties. In my class I am only dealing with string values so it works nice but if you are trying to copy anything other then a string, number or boolean it will make a reference.
Anyways, great site and thanks for the inspiration.
[...] for me, Manish Jethani has an excellent blog post in which he implements an OrderedObject class that keeps a record of property order. A simple and [...]