Tutorials Books Videos Forums

Change the theme! Search!
Rambo ftw!

Customize Theme


Color

Background


Done

AS1 OOP: Controlling OOP

by senocular   | filed under Object-Oriented Programming

This is an archived tutorial from the kirupa.com legacy collection. It covers software that may no longer be available, but it is kept online because the ideas still hold up.

Introduction

The way Actionscript works is not really all that hard to understand. Most of the concepts so far are fairly easy to get a grasp on and implement in practice. In fact, there’s a general basic foundation for everything that happens with Actionscript. It’s all based on basic object properties and behavior. All that inheritance stuff? It’s all handled through simple objects and the properties that define those objects. What’s more is that the way Flash handles inheritance is also through automatically created object properties, namely __proto__ and __constructor__.

__proto__

The __proto__ property is a property in all objects which is a reference to the next inherited object in an object’s inheritance chain. It’s the __proto__ reference that lets an object know what methods and properties are being directly shared with it. Like constructor, __proto__ is an automatic property that is added for you in creating an object. Any object instance of any class has a __proto__ property and it uses __proto__ to access to that class’s prototype object as __proto__ is a reference to it. It’s the __proto__ that lets any object know where to look when it doesn’t have a method or property of its own; when an object needs to use a shared method or property within that objects inheritance chain. The __proto__ property makes up the links in that chain.

[ __proto__ links classes with subclasses (prototypes) ]

What happens when you reference any property or any method in an object is that Flash goes through that object and looks through all the properties contained directly within that object. These include any properties put there by that object’s constructor or objects that you specifically defined in the instance manually. If the referenced property isn’t found there, Flash then looks to the next object in the inheritance chain – the object the current object is sharing properties from, most likely, the prototype of that object’s class. Flash knows how to get to that object based on the __proto__ property as it’s the reference defining that connection. If the property still isnt found in that object, Flash continues to search through the __proto__ reference in that object to go up the chain further until there is no more objects to search (or until the property trying to be accessed is found).

The only object that doesn’t have a __proto__ property is Object.prototype as it is the end of the line for object inheritcance. Since all objects by default inherit from the Object class the object class itself cannot inherit from anything else. Otherwise there would be an infinite loop in inheritance since every __proto__ would eventually come back around to Object.prototype. For example, simply put the following lines in a Flash movie and test it.

Object.prototype.__proto__ = {};

In return you’ll get a repeating loop of trace message errors saying:

"256 levels of prototype chain were exceeded. This is probably a circular prototype chain. Further execution of actions has been disabled in this movie."

The reason being that if Object.prototype’s __proto__ was to another object, since that object’s __proto__ references back to Object.prototype, you have yourself a circular, non-ending prototype as the error indicated.

__constructor__

The tradition of double underscore padded variables continues with the __constructor__ property. The final of the 3 ‘automatic’ properties in instances, __constructor__ is a property referencing the constructor of a class instance primarily for use by the super operator. Basically its more or less a repeat of the constructor property. However, its purpose is not to tell you what the constructor of an instance is, but rather to tell super what the constructor is. As such, __constructor__ is more of a prototype object property. All class instances have them, but those in use by the super operator are those in prototype objects (where super looks to figure out what your instance’s class constructor is).

Just as any object instance looks to its own __proto__ for the next shared object in its inheritance chain, super uses __constructor__ to find an instance’s constructor. Super, however, doesn’t use the instance’s own __constructor__ property, it uses the instance’s class prototype __constructor__ property, or to that instance, its __proto__.__constructor__. After all, the instance’s constructor is not the super class constructor. Its still its own constructor. The instance’s class prototype’s constructor, however, would be the instances super class constructor. So it’s there the super must look.

You can think of these double underscore properties as road signs, pointing in the direction of prototype objects and constructors.

[ __proto__ and __constructor__ as pointing signs ]

These road signs, however, are for internal use only. So they’re more along the lines of road signs in a secret military base. Luckily for us, we know where that base is and can sneak in during nights to change those signs around.

A quick example of switching those signs, or at least __constructor__, can be seen with email. Because email has certain common elements that you would find with any other type of more general mail, things like a recipient and a message, it can be made as a subclass of a mail super class. As a subclass of mail, email would need its instances to have mail properties defined for them when created, thus super is utilized to provide that. But what if some sneaky advertiser came in and changed e-mail's __constructor__ property

Spam = function(){
  this.to = "everyone in your address book";
  this.message = "ENLARGE YOURSELF BY 200%!";
};
Mail = function(recipient, message){
  this.recipient = recipient;
  this.message = message;
};
Email = function(subject, recipient, message){
  this.subject = subject;
  super(recipient, message); // uses __constructor__
};
Email.prototype = new Mail();
myMail = new Email("greetings", "you", "hello! your friend, xxx");
trace(myMail.subject); // greetings
trace(myMail.recipient); // you
trace(myMail.message); // hello! your friend, xxx
// change email’s __constructor__ and witness the results
Email.prototype.__constructor__ = Spam;
myMail = new Email("greetings", "you", "hello! your friend, xxx");
trace(myMail.subject); // greetings
trace(myMail.recipient); // everyone in your address book
trace(myMail.message); // ENLARGE YOURSELF BY 200%!

You can see what happened with super after the email.prototype.__constructor__ was changed from pointing to its default of mail to instead the spam function. The super call no longer saw mail as being the super class of email, it saw spam as the super class, and as such, the definitions provided by spam were added into the myMail instance within the constructor call.

Note that inheritance was established for the prior example. For classes not inheriting from other classes, you have no __constructor__ property in the class’s prototype. Because its an instance property, it’s assigned from the instance created in establishing inheritance with a new super class defined as the prototype object. Default prototype obejcts are without __constructor__ properties but, they do have constructor properties, and they reference the class constructor function.

MyClass = function(){};
trace(MyClass.prototype.__constructor__); // traces undefined
trace(MyClass.prototype.constructor); // traces [type Function]
trace(MyClass.prototype.constructor == MyClass); // traces true

Similarly, the constructor function itself, as a Function object instance, also is without a __constructor__ property.

MyClass = function(){}
trace(MyClass.__constructor__); // traces undefined
trace(MyClass.constructor); // traces [type Function]
trace(MyClass.constructor == Function); // traces true

With anything you create using the new keyword, though, you can be confident that it will have a __constructor__ property.

Coming Together With OOP

With all that’s been said and done, we can now begin to see how Flash handles its objects in OOP with Actionscript, most of which revolves around certain automatically assigned properties which handles object interaction.

Functions: Automatic Properties
constructor Reference to the Function Object
__proto__ Reference to Function.prototype
prototype A generic Object instance
Prototype: Automatic Properties
constructor Reference to the Function Object
__proto__ Reference to Object.prototype
Class Instances (new Function()): Automatic Properties
constructor Reference to constructor function
__constructor__ Reference to constructor function
__proto__ Reference to constructor function’s prototype

The big player being __proto__ controlling inherited properties in methods. Also important, though, is __constructor__ for when a class instance is created as a prototype object, that object can then correctly reference the super class for instances of that prototype’s class. Its those two properties that define inheritance for Flash Actionscript 1.0.

Extends

Based on the fact that inheritance for objects is completely controlled through __proto__ and __constructor__ a new means of establishing inheritance can be formulated based on manually altering these values. In describing each, these values were both changed to demonstrate their role. Used together, they can effectively define inheritance for an object or class – an alternative methods of establishing inheritance opposed to subclass.prototype = new superClass(); which, in effect, is just assigning __proto__ and __constructor__ for the prototype in the first place.

Enter extends. Extends is a method for extending a class given a new subclass which is to be derived from it. Actionscript doesn’t already have an extends keyword or method, but given your new-found knowledge of __proto__ and __constructor__ and how they determine inheritance, one can easily be made. All it would need to do is take one class and make it inherit from another class, and what with? __proto__ and __constructor__.

Because class constructors are functions, and the foundation definition of a class, our new extends method can be made as a prototype method of the Function object. That way a class constructor can use it just as any other object would use any of its methods. As a Function.prototype, the extends method can then be used on a subclass to define a __proto__ and a __constructor__ based on a passed super class effectively defining the inheritance chain to that super class. Here’s what you get.

Function.prototype.extends = function(superClass){
  this.prototype.__proto__ = superClass.prototype; // for inheritance
  this.prototype.__constructor__ = superClass; // for super
};
// Use
subclass.extends(superclass);

What you have here is the defining of a class prototype’s __proto__ and __constructor__ properties to point to a correspoding prototype and constructor to represent a super class. If you think about it, this is exactly what using subclass.prototype = new superClass() is doing since the super class instance will have a __proto__ to its class’s prototype object and a __constructor__ to the class constructor, only here a) you aren’t replacing the prototype object and b) you don’t get properties of the super class defined for the prototype object as specified in the super class constructor.

The fact that you aren’t replacing the prototype object when using extends is it’s big advantage. This allows you to have defined values for your prototype before defining inheritance. It also allows an easy means for changing inheritance at run time without having to completely re-define the class. On top of that, the fact that you aren’t using a super class instance as prototype object means you don’t run into that prototype instance issue when attempting to keep track and count all instances of a certain class that are in use.

The big disadvantage is that its not a standard. It works just fine, it’s just that Macromedia suggests using subclass.prototype = new superClass() to establish inheritance. For more on Macromedia’s standards with OOP, see their standards whitepaper. That of course, stops few from using it.

Now as extends exists here, its use is specific to classes and class inheritance. Using the same concept, you can also change the inheritance of class instances. Instances, however, differ slightly in that they don’t specifically use a __constructor__. The use of __constructor__ is for super through prototype objects. With instances, it’s the prototype object, or more specifically __proto__, that determines that. So for instances, to effectively change what an instance perceives to be it’s own class, you would change its __proto__ property.

Object.prototype.setClass = function(class){
  this.constructor = class;
  this.__proto__ = class.prototype;
};
// Use
instance.setClass(class);

This method takes an instance and changes its class association to be a new class – that of the class passed in to the call. For all events and purposes for that instance, in Flash, it’s considered an instance of that new passed in class. Here, though, the issue of defined property values becomes a little more relevant. Setting a class for an instance this way won’t run the constructor for that instance, just set up the inheritance chain for that instance to follow the new class. You may want to call the constructor for that instance if you want it to be initialized, either in setClass or separately.

instance.setClass(class);
instance.constructor(constructor_arguments);

Where setClass comes especially handy is with movieclips. Some of the shortcomings found in Object.registerClass can be handled with this setClass method, most particularly for defining a class association for pre-existing movieclips and movieclips created with createEmptyMovieClip. Instead of using Object.registerClass, just call setClass for your movieclip and tell it what to be. Then that movieclip will inherit all methods from that class’s prototype and be able to use them as if it were initially created as an instance of that class (remember to make the class a subclass of MovieClip).

Example:

[ empty movieclip (triangle) dynamically given class ]

Object.prototype.setClass = function(class){
  this.constructor = class;
  this.__proto__ = class.prototype;
};
Faller = function(ground){
  this.ground = ground;
  this.velocity = 0;
};
Faller.prototype = new MovieClip();
Faller.prototype.onEnterFrame = function(){
  this.velocity++;
  this._y += this.velocity;
  if (this._y >= this.ground){
  this._y = this.ground;
  this.velocity *= -1;
  }
};
this.createEmptyMovieClip("triangle", 1);
with (triangle){
  // draw the triangle in the empty clip
  // position
  _x = 150;
  _y = 20;
  beginFill(0xaaaaaa, 100);
  lineStyle(2,0,100);
  moveTo(0,-10);
  lineTo(10,10);
  lineTo(-10,10);
  lineTo(0,-10);
  endFill();
}
// set the class
triangle.setClass(Faller);
// call the constructor to define ground property
triangle.constructor(100);

That wraps up this tutorial. A huge thank you to all of you who buy kirupa's books, became a paid subscriber, watch the videos, and/or interact on the forums. Your support is what keeps writing like this online! 😇

senocular

This tutorial was written by senocular, also known as Trevor McCauley. He has been one of this community's most generous teachers since the early Flash days, and he is still around: find him on senocular.com and on the forums.

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends

:: Copyright KIRUPA 2026 //--