In ActionScript 3, classes (and functions as well) are objects that can be manipulated like any other object. The language provides us with some constructs to facilitate this, and they are an important part of the programmer’s toolkit.
We need to be able to traverse the connections among the Class, an instance of the Class, and the name of the Class.
From name to Class; from instance to Class
First, you want to be able to get hold of a Class object, either from its package path and class name:
import flash.utils.*;
var myClass:Class = getDefinitionByName("com.myDomain.myPackage.SomeClass");
or from an instance of the class:
var myClass:Class = myInstance.constructor;
Here are a few simple ways you can use these:
-
The Class object is a factory for making instances of its class, so using getDefinitionByName() you can write a factory method to instantiate objects of types specified by Strings, e.g. in an XML file:
var myClass:Class = getDefinitionByName("com.myDomain.myPackage." + xmlData.@type); var myObject:Object = new myClass(); -
Run-time enforcement of an abstract class:
public function MyClass() { super(); if (this.constructor == MyClass) { throw new IllegalOperationError("AbstractException"); } } -
Suppose a game character is collecting items such as gems or weapons or vegetables, and all you need to know about the items is their type. You don’t have to hang on to the items themselves; you can store the collection as a Dictionary indexed by class objects:
private var _collection:Dictionary = new Dictionary(true); . . . private function collect(item:Object):void { var itemClass:Class = item.constructor; if (_collection[itemClass] == null) { _collection[itemClass] = 1; } else { _collection[itemClass]++; } }
From Class to class name; from instance to class name
I’ll just show my getClassName() function here:
import flash.utils.*;
public function getClassName(o:Object):String
{
if (o is Class)
{
var s:String = o.toString(); // "[class SoAndSo]”
return s.substring(7, s.length - 1);
}
else
{
var fullClassName:String = getQualifiedClassName(o);
var i:int = fullClassName.lastIndexOf(”::”);
if (i == -1)
{
return fullClassName;
}
return fullClassName.slice(i + 2);
}
}
The toString() method is defined in the root Object class, and it can be redefined in your own classes. It’s called whenever the String representation of an object is needed. For example in getClassName() I could have written
var s:String = "" + o;
which would have implicitly invoked o.toString(). The trace() function also uses toString(). So it’s a good idea to implement toString() in your classes. I usually start out by doing this:
public override function toString():String
{
return getClassName(this);
}
and then add whatever specific data I need to show into it.
Related ActionScript 3 Tip of the Day by Senocular: #73
From Class to Class
Here’s the last basic class-slinging tool, and I believe it’s one that not many Flash programmers are aware of. Suppose you want to know if class A is derived from class B. You might think you’d have to make an instance of A and use the is operator on it. And that’s OK if you don’t have to come up with parameters for the constructor. But there’s a cleaner way:
public function isDerived(childClass:Class, ancestorClass:Class):Boolean
{
if (ancestorClass.prototype.isPrototypeOf(childClass.prototype))
{
return true;
}
return false;
}
Now you may say yeccch, we’ve left the prototype behind, that’s old-school AS1 programming, and you’d certainly be correct in a way: In AS1 there was no way to simulate classes except by mucking with the prototype, and in AS2 the compiler simulated classes under the hood by mucking with the prototype, and in AS3 we have true class inheritance. So there’s almost certainly no need to simulate classes in AS3. But the prototype, and the isPrototypeOf() function, are not going away any time soon; they’re in the ECMA spec, so they must be retained in the language. I believe I can guarantee, though, that aside from this isDerived() function, there is NO other legitimate use case for isPrototypeOf() in AS3! The prototype itself is a different matter, and I mentioned a use case for placing properties there in a comment to my recent post Advanced Users May Choose.
Related ActionScript 3 Tip of the Day by Senocular: #74
What can you do with isDerived()? Suppose my game character is collecting various kinds of Gems, such as Rubies, Sapphires, and Diamonds, and various kinds of Vegetables, such as Rutabagas, Kohlrabi, and JerusalemArtichokes. He’s saving them in a Dictionary as in the example above, and I need to know how many Gems or how many Vegetables he has:
private function numInCollection(collectionClass:Class):uint
{
var n:uint = 0;
for (var key:* in _collection)
{
var c:Class = key as Class;
if (c == collectionClass
|| isDerived(c, collectionClass))
{
n += _collection[key];
}
}
return n;
}
Summary of indexed collections in AS3
- Object: properties indexed by Strings
- Array: properties indexed by Numbers
- Dictionary: properties indexed by Objects
Occasionally I meet a programmer who indexes an Array object’s properties using Strings. Of course this works, but it works because the array is an Object; if you’re not using Numbers as indices, then you’re just wasting space by declaring the collection as an Array. You could make it a MovieClip and it would work just as well!

