There are lots of ways to check the type of an object in AS3. These include the is operator, the deprecated instanceof operator, the constructor field, and a combination of getQualifiedClassName and getDefinitionByName. Which is fastest, cleanest, and most effective? Today’s article puts them all to the test to find out!

Let’s go over the contenders so we know what we’re comparing here. First is the is operator, which is clearly the most common solution to the problem. Its syntax is simply this:

boolResult = myObject is SomeClass

The is operator was introduced in Flash 9 with AS3, but the instanceof keyword from AS2 lingers on. It’s less effective than is, but we should still test it. Usage is extremely similar to is:

boolResult = myObject instanceof SomeClass

Next is the constructor field that every Object has. This can be used as a primitive version of is or instanceof when you only need to compare classes directly and don’t care about inheritance. Here’s how you’d do that:

boolResult = myObject.constructor == SomeClass

Lastly, there is the combination of getQualifiedClassName and getDefinitionByName. This is by far the most complicated approach and still is only useful for directly comparing classes. Here’s how it works:

boolResult = Class(getDefinitionByName(getQualifiedClassName(myObject))) == SomeClass

Now let’s put these to the test with a little app. We’ll create an empty Parent class and an empty Child class that derives from it and run four tests for each approach:

  • parent is/instanceof/== Parent
  • parent is/instanceof/== Child
  • child is/instanceof/== Parent
  • child is/instanceof/== Child
////////////
// Parent.as
////////////
package
{
	public class Parent {}
}
 
///////////
// Child.as
///////////
package
{
	public class Child extends Parent {}
}
 
///////////////////////
// IsInstanceOfSpeed.as
///////////////////////
package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class IsInstanceOfSpeed extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",") + "\n");
		}
 
		public function IsInstanceOfSpeed()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			const REPS:int = 1000000;
			var i:int;
			var beforeTime:int;
			var afterTime:int;
			var bool:Boolean;
			var parent:Parent = new Parent();
			var child:Child = new Child();
 
			row("Operation", "Time");
 
			//////////////
			// CONSTRUCTOR
			//////////////
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent.constructor == Parent;
			}
			afterTime = getTimer();
			row("parent.constructor == Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent.constructor == Child;
			}
			afterTime = getTimer();
			row("parent.constructor == Child", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child.constructor == Parent;
			}
			afterTime = getTimer();
			row("child.constructor == Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child.constructor == Child;
			}
			afterTime = getTimer();
			row("child.constructor == Child", (afterTime-beforeTime));
 
			///////////
			// GETCLASS
			///////////
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = Class(getDefinitionByName(getQualifiedClassName(parent))) == Parent;
			}
			afterTime = getTimer();
			row("getClass(parent) == Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = Class(getDefinitionByName(getQualifiedClassName(parent))) == Child;
			}
			afterTime = getTimer();
			row("getClass(parent) == Child", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = Class(getDefinitionByName(getQualifiedClassName(child))) == Parent;
			}
			afterTime = getTimer();
			row("getClass(child) == Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = Class(getDefinitionByName(getQualifiedClassName(child))) == Child;
			}
			afterTime = getTimer();
			row("getClass(child) == Child", (afterTime-beforeTime));
 
			////////////
			// PROTOTYPE
			////////////
 
			/////
			// IS
			/////
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent is Parent;
			}
			afterTime = getTimer();
			row("parent is Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent is Child;
			}
			afterTime = getTimer();
			row("parent is Child", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child is Parent;
			}
			afterTime = getTimer();
			row("child is Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child is Child;
			}
			afterTime = getTimer();
			row("child is Child", (afterTime-beforeTime));
 
			/////////////
			// INSTANCEOF
			/////////////
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent instanceof Parent;
			}
			afterTime = getTimer();
			row("parent instanceof Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = parent instanceof Child;
			}
			afterTime = getTimer();
			row("parent instanceof Child", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child instanceof Parent;
			}
			afterTime = getTimer();
			row("child instanceof Parent", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				bool = child instanceof Child;
			}
			afterTime = getTimer();
			row("child instanceof Child", (afterTime-beforeTime));
		}
	}
}

Run the test

I tested this app using the following environment:

  • Release version of Flash Player 14.0.0.125
  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.9.2
  • Google Chrome 35.0.1916.153
  • ASC 2.0.0 build 354130 (-debug=false -verbose-stacktraces=false -inline -optimize=true)

And got these results:

Operation Time
parent[“constructor”] == Parent 88
parent[“constructor”] == Child 84
child[“constructor”] == Parent 89
child[“constructor”] == Child 88
getClass(parent) == Parent 466
getClass(parent) == Child 475
getClass(child) == Parent 446
getClass(child) == Child 447
parent is Parent 4
parent is Child 3
child is Parent 4
child is Child 4
parent instanceof Parent 26
parent instanceof Child 29
child instanceof Parent 28
child instanceof Child 32

Checking Object Type

The first observation to make is that the object and class type parameters to each test made no difference at all. That means it’s just as fast (or slow) to check if an object is a Child or Parent regardless of which it actually is.

The differences lie in the method used to check. By far the worst is the getClass approach that combines getQualifiedClassName and getDefinitionByName. It’s taking 5x longer than the next-worse solution and still not supporting any inheritance. That next-worse solution is the constructor property which also doesn’t support inheritance. It’s about 2.7x slower than the second-best solution: instanceof. The instanceof operator is about 7x slower than the fastest solution: is.

This leaves is as by far the fastest solution, the solution with that best supports inheritance, and doesn’t have any awkward conditions like getClass requiring public classes. It is definitely the best way to check an object’s type.

Spot a bug? Have a question or suggestion? Post a comment!