Sometimes, you want to know the datatype of an object at runtime. The most common thing to do in ActionScript 3 is use the is keyword to see if an object is an instance of a specific class. For example, you use exampleObject is Sprite to see if something is a Sprite (or any subclass of Sprite). However, there are times when you want to use the actual class in your code to create a new instance, or to do something a little more arcane. There are a couple simple ways to access the datatype of an object and place it in a variable.
Method 1: Combine a couple flash.utils functions
The first way to get an object’s class at runtime takes requires calls to a couple useful functions that live in the flash.utils package:
import flash.utils.getQualifiedClassName; import flash.utils.getDefinitionByName; var example:Sprite = new Sprite(); var exampleName:String = getQualifiedClassName( example ); var exampleType:Class = getDefinitionByName( exampleName ) as Class; trace( exampleType == Sprite ); //output: true
Start by calling the function flash.utils.getQualifiedClassName(), and pass in the object. It will return a string that includes the full class name, including the package. For example, passing in a Sprite object will return the String value "flash.display::Sprite". Next, call the function flash.utils.getDefinitionByName(), and pass in the String value that you just received. It will return a reference to the object’s class. An equality check is included in the code above to demonstrate that exampleType is actually the Sprite class.
Mainly, I’ve included this first method of extracting a class from an instance because the two utility functions used in the example above are quite useful in other contexts. However, the second method is much simpler, if a little more obscure.
Method 2: The constructor property
Every object in ActionScript 3 has a property named constructor. According to the documentation, it is a reference to the datatype used to instantiate the object. In other words, every object can tell you the Class (or Function, since AS3 still supports ECMAScript function prototypes) used to create it with one simple property lookup. How simple!
var example:Sprite = new Sprite(); var exampleType:Class = Object( example ).constructor; trace( exampleType == Sprite); //output: true
What’s interesting, and not immediately obvious (unless you read the documentation thoroughly), is that if you try to access the constructor property in the strict mode (which is on by default in the AS3 compiler), you’ll get a compiler error. However, the documentation notes that dynamic objects don’t cause this error. We can use that fact to create an easy workaround because everything is an Object, and Object happens to be a dynamic class. As you can see in the code above, a simple cast makes the error go away.
Personally, I prefer the second method because it takes only a simple property lookup, and it requires no calls to functions with long names. Again, though, those functions can be quite useful in other contexts, so it’s worth making note of them.
I have wrapped the flash.utils methods in a Util class that caches the object definitions… seeing Class definitions are static, it works out pretty well. That way I can cache all sorts of metadata etc on the classes.
This is the first time I have really seen any use for the constructor property though well done
If I find time ill clean it up and post a link
The as3-commons projects came forth out of Spring Actionscript and offers quite an extensive reflection library, you might like to check it out here:
AS3 Commons Reflect
Nice find Josh, I wasn’t familiar with this approach. Not only does it look cleaner in my opinion but based on some rudimentary testing it appears to be about 4 times faster as well.
I was just about to ask about the relative speeds – should have known you’d check, Ben!
This is great stuff, Josh. Thanks for the post.
Would there be a way, using this method, to determine in a setter function what class was trying to set the value in another class?
So if a variable was only supposed to be able to be set from a specific class, others would error out?
There is no way to get the object that called a function, unless you require that it gets explicitly passed in. Something like this would work:
public function setExample(exampleValue:Object, caller:SpecialType):void { if(caller == null) { throw new Error("Caller must be of type SpecialType."); } this._example = exampleValue; }Personally, I don’t like that approach. A better one might be to use namespaces.
You can define the same namespace separately in each class:
…and then use it instead of public for your setter:
only_special_type function set example(value:Object):void { this._example = value; }That won’t stop people from using your setter if they know how to define the same namespace, but they’ll have to explicitly make that choice, so it adds a stronger barrier to entry.
Sweet, thanks. I have been wondering how to do that for a little while now.
[...] like the FontAsset class.. how do I get a pure Font class? After some researching, I find this post which describes the "constructor" property of all objects.. cool. This will let you simulate [...]
[...] Get the class used to create an object instance in AS3 – Josh Talks Flash [...]