46

How do you get an instance of the actionscript class Class from an instance of that class?

In Python, this would be x.__class__; in Java, x.getClass();.

I'm aware that certain terrible hacks exist to do this, but I'm looking for a built-in language facility, or at least a library routine built on something reliable.

Glyph
  • 31,152
  • 11
  • 87
  • 129

3 Answers3

69

You can get it through the 'constructor' property of the base Object class. i.e.:

var myClass:Class = Object(myObj).constructor;
Gerald
  • 23,011
  • 10
  • 73
  • 102
  • As far as I know it's my own gem, though the Adobe docs for the Object class mentions the constructor property and what it is. I've never seen it used that way anywhere else. – Gerald Oct 15 '08 at 11:12
  • 1
    Some more discussion here: http://joshblog.net/2009/05/11/retrieve-the-class-used-to-instantiate-an-object-in-as3/ One slight alternative would be to do: var classRef:Class = myObj["constructor"] as Class; This also gets around the strict compiler checks. Not sure which one performs better. mike chambers – mikechambers Jul 13 '09 at 21:30
  • 6
    This does not work on objects that subclass Proxy, such as XML. See this answer - http://stackoverflow.com/questions/468925/in-actionscript3-how-do-you-get-a-reference-to-an-objects-class/472300#472300 – Richard Szalay Jul 26 '09 at 08:51
  • That is really nice. Neatly avoids a problem I was having with referencing a class on the main stage. Thanks a bunch – Glitcher Aug 09 '13 at 12:22
14

Any reason you couldn't do this?

var s:Sprite = new flash.display.Sprite();

var className:String = flash.utils.getQualifiedClassName( s );
var myClass:Class = flash.utils.getDefinitionByName( className ) as Class;

trace(className ); // flash.display::Sprite
trace(myClass); // [class Sprite]

var s2 = new myClass();
trace(s2); // [object Sprite]

I don't know a way to avoid round-tripping through a String, but it should work well enough.

fenomas
  • 11,131
  • 2
  • 33
  • 57
  • 2
    This would work, but the performance for getQualifiedClassName and getDefinitionByName is pretty poor. mike chambers – mikechambers Jul 13 '09 at 21:25
14

The accepted (and currently most popular answer) has some flaws. The answer serves for this specific use case, but the comments have expanded the answer to a seeming general solution.

But it is not a type-safe solution in certain cases, and it doesn't address all possible objects. The idea that XML is not supported has been addressed well enough here and elsewhere, but the type-safe idea has not.

The assumption made is that it is an class object created by the programmer. Here are some tests that I set up (this is in strict mode, but a local test). Note the int test results:

var sprite:Sprite = new Sprite();
var xml:XML = new XML();
var testInt:int = 2;
var testClass:TestClass = new TestClass();
var testAnon:Object = {};

trace("classname 1 = " + getQualifiedClassName(sprite));
trace("myclass 1 = " + getDefinitionByName(getQualifiedClassName(sprite)));
trace("constructor a 1 = " + Object(sprite).constructor);
trace("constructor a 1 = " + (Object(sprite).constructor as Class));
trace("constructor b 1 = " + sprite["constructor"]);
trace("constructor b 1 = " + (sprite["constructor"] as Class));
trace("...");
trace("classname 2 = " + getQualifiedClassName(xml));
trace("myclass 2 = " + getDefinitionByName(getQualifiedClassName(xml)));
trace("constructor a 2 = " + Object(xml).constructor);
trace("constructor a 2 = " + (Object(xml).constructor as Class));
trace("constructor b 2 = " + xml["constructor"]);
trace("constructor b 2 = " + (xml["constructor"] as Class));
trace("...");
trace("classname 3 = " + getQualifiedClassName(testInt));
trace("myclass 3 = " + getDefinitionByName(getQualifiedClassName(testInt)));
trace("constructor a 3 = " + Object(testInt).constructor);
trace("constructor a 3 = " + (Object(testInt).constructor as Class));
trace("constructor b 3 = " + testInt["constructor"]);
trace("constructor b 3 = " + (testInt["constructor"] as Class));
trace("...");
trace("classname 4 = " + getQualifiedClassName(testClass));
trace("myclass 4 = " + getDefinitionByName(getQualifiedClassName(testClass)));
trace("constructor a 4 = " + Object(testClass).constructor);
trace("constructor a 4 = " + (Object(testClass).constructor as Class));
trace("constructor b 4 = " + testClass["constructor"]);
trace("constructor b 4 = " + (testClass["constructor"] as Class));
trace("...");
trace("classname 5 = " + getQualifiedClassName(testAnon));
trace("myclass 5 = " + getDefinitionByName(getQualifiedClassName(testAnon)));
trace("constructor a 5 = " + Object(testAnon).constructor);
trace("constructor a 5 = " + (Object(testAnon).constructor as Class));
trace("constructor b 5 = " + testAnon["constructor"]);
trace("constructor b 5 = " + (testAnon["constructor"] as Class));
trace("...");

With TestClass defined as:

package
{
    public class TestClass
    {
    }
}

Results:

classname 1 = flash.display::Sprite
myclass 1 = [class Sprite]
constructor a 1 = [class Sprite]
constructor a 1 = [class Sprite]
constructor b 1 = [class Sprite]
constructor b 1 = [class Sprite]
...
classname 2 = XML
myclass 2 = [class XML]
constructor a 2 = 
constructor a 2 = null
constructor b 2 = 
constructor b 2 = null
...
classname 3 = int
myclass 3 = [class int]
constructor a 3 = [class Number]
constructor a 3 = [class Number]
constructor b 3 = [class Number]
constructor b 3 = [class Number]
...
classname 4 = src::TestClass
myclass 4 = [class TestClass]
constructor a 4 = [class TestClass]
constructor a 4 = [class TestClass]
constructor b 4 = [class TestClass]
constructor b 4 = [class TestClass]
...
classname 5 = Object
myclass 5 = [class Object]
constructor a 5 = [class Object]
constructor a 5 = [class Object]
constructor b 5 = [class Object]
constructor b 5 = [class Object]
...

Beyond any current testing, there is fairly good reason to use getDefinitionByName over the constructor methods. The getDefinitionByName method allows :

  • Adobe to develop internal solutions for the (current and future) problematic areas
  • you would not have to change your code for future Adobe developments
  • you do not have to develop two (or more) separate methods of dynamic instantiation.

It may be slower now, but in the future there may be improvements from Adobe's side that would address the speed issue.

(For example, it used to be that uint was far slower in for-loops than int, so a lot of conversion code was set up to use the faster int. It was a fairly simple issue to solve, so Adobe fixed it, and now there is a lot of code that jumps through some unnecessary hoops to achieve an outdated goal.)

Since the getDefinitionByName method works correctly in all cases, code should be developed using that method, and then work to get Adobe to fix the speed issue.

iND
  • 2,663
  • 1
  • 16
  • 36