Associative arrays are also referred to as dictionaries or maps. A regular array uses numbers to index into the array, whereas an associative array uses objects as indexes (called keys).
While C++ and Java use libraries for associative arrays, in Python, Ruby and ActionScript they are first-class language elements (in Perl they are hashes). The ActionScript/JavaScript approach seems slightly odd because an associative array is just an Object, or rather an Object is an associative array. It turns out this is not so strange; in Python, for example, all members of an object are held in a dictionary.
ActionScript provides a convenient syntax for creating dictionaries, very similar to Python's dictionary definition. You define the dictionary using curly braces, and divide keys from values using colons:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application name="AssociativeArrays" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:creationComplete>
include "../../Mindview/includes/show.as"
var dict:Object = { foo:"hello", bar:"world", baz: "goodbye" }
t.show("dict.foo: " + dict.foo)
t.show("dict['bar']: " + dict['bar'])
for(var key:String in dict)
t.show(key + ": " + dict[key])
for each(var val:String in dict)
t.show(val)
</mx:creationComplete>
</mx:Application>
Here's the output:
dict.foo: hello dict['bar']: world baz: goodbye bar: world foo: hello goodbye world hello
Notice that, even though we're using dictionary-definition syntax, we are actually creating an object, as you can see by the dot-access in dict.foo. But you can also access elements using array-indexing syntax as seen in dict['bar'], although you must put the key in quotes (even though quotes are not necessary when defining the key within curly braces).
You can now see the fundamental difference between the for and for each statements: both iterate through the elements of an object, but for produces the keys and for each produces the values. This explains the odd results when using for and for each with Array objects:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application name="ForAndForEach" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:creationComplete>
include "../../Mindview/includes/show.as"
var a:Array = "AEIOU".split('')
for(var k:* in a)
t.show(k + " typeof k: " + typeof k)
for each(var v:* in a)
t.show(v + " typeof v: " + typeof v)
</mx:creationComplete>
</mx:Application>
The k:* is declaring k as an unknown type, since this is a generic function and we don't know what's in the array.
When you say for, you're just iterating through the keys of the Array, which are just the numerical indices:
0 typeof k: number 1 typeof k: number 2 typeof k: number 3 typeof k: number 4 typeof k: number A typeof v: string E typeof v: string I typeof v: string O typeof v: string U typeof v: string
Because the curly-brace syntax produces an object and not just a plain dictionary, it is also a syntax for creating anonymous objects:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application name="AnonymousObjects" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:creationComplete>
include "../../Mindview/includes/show.as"
var times:Number = 10
var anon:Object = {
field1: "Hello, anonymous world",
field2: 1066,
function1: function():String { return this.field1 },
function2: function():Number { return times * this.field2}
}
t.show(anon.field1)
t.show(anon.field2)
t.show(anon.function1())
t.show(anon.function2())
</mx:creationComplete>
</mx:Application>
This produces:
Hello, anonymous world 1066 Hello, anonymous world 10660
Note that anon also exhibits closure behavior; it captures the value of times which is defined outside of the scope of anon. This is not, however, a full proof of closure behavior in ActionScript; here is an article on closures that gives you the details.
In the original example in this section, the dictionary was defined like this:
var dict:Object = { foo:"hello", bar:"world", baz: "goodbye" }
This syntax automatically turns the keys into strings, even though they are not quoted. But in the general case you are not restricted to strings as keys; you can use any object as a key.
The following example not only shows the use of objects as keys, but it also introduces the Dictionary class, which has a somewhat subtle difference from using the basic Object dictionary. This reuses com.mindviewinc.test.AutoID, seen earlier in this article:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application name="ObjectsAsKeys" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:creationComplete>
include "../../Mindview/includes/show.as"
import com.mindviewinc.test.AutoID
function display(x:Object):void {
for(var k:* in x)
t.show(k + ":" + x[k] + ", typeof k: " + typeof k +
", typeof x[k]: " + typeof x[k])
}
var a:AutoID = new AutoID(), b:AutoID = new AutoID(), c:AutoID = new AutoID()
var dict1:Object = {a:'x', b:'y', c:'z'}
display(dict1)
t.show("dict1[b]:" + dict1[b]) // Undefined
var dict2:Object = new Object()
dict2[a] = 'one'
dict2[b] = 'two'
dict2[c] = 'three'
display(dict2)
t.show("dict2[b]:" + dict2[b])
var dict3:Dictionary = new Dictionary()
dict3[a] = 'one'
dict3[b] = 'two'
dict3[c] = 'three'
display(dict3)
t.show("dict3[b]:" + dict3[b])
</mx:creationComplete>
</mx:Application>
The output tells the story:
b:y, typeof k: string, typeof x[k]: string c:z, typeof k: string, typeof x[k]: string a:x, typeof k: string, typeof x[k]: string dict1[b]:undefined B:two, typeof k: string, typeof x[k]: string A:one, typeof k: string, typeof x[k]: string C:three, typeof k: string, typeof x[k]: string dict2[b]:two A:one, typeof k: object, typeof x[k]: string B:two, typeof k: object, typeof x[k]: string C:three, typeof k: object, typeof x[k]: string dict3[b]:two
dict1 uses the "convenience syntax," but this ignores the attempt to use the objects a, b and c. Instead it turns the key names into strings, so when we say dict1[b] it doesn't have a value for b the object as a key.
With dict2 we explicitly assign using the square-bracket syntax and the un-quoted a, b and c. This time it does use the objects as keys, but you can see from the output that it uses their string representation (which is oftentimes just fine). Dictionary uses the key object's identity rather than its string representation, which you can see from the typeof expression in dict3's output.