Tutorials Books Videos Forums

Change the theme! Search!
Rambo ftw!

Customize Theme


Color

Background


Done

AS1 OOP: Custom Object Classes

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

Custom objects are what characterize OOP. After all, they don’t call it Object Oriented Programming for nothing. A Class is the definition of your custom object. It is often compared to the blueprint, like the blueprint of a house. Blueprints are schematics which show how such a building is built and constructed. One blueprint can be used to build one house or many houses of that same type which will exist at different addresses. Chances are you've probably seen a lot of houses that look more or less exactly alike in the same neighborhood. These houses were probably all made with the same blueprint which saves the developers of that particular community both time and money. A custom object class works very much the same way.

Class Constructors

Class instances in Actionscript 1.0 are defined with a constructor function. Constructor functions are functions that are used to create or construct an instance of your new custom object. They define what properties and what methods each instance of the class will have when created.

To the naked eye, constructor functions look just like any other function. In fact, there is no real technical difference between the constructor function of a class and any other function. The difference comes only in its use. With that, keep in mind that the same rules for functions apply. If you define a function in _root and decide to use that function in some timeline other than _root, you would need to reference that function through _root. It’s not readily available for use in all timelines, just the timeline it was defined. If you do want the function, or class constructor in our case, to be globally available everywhere, you might consider defining it in _global.

Here is a simple example of a House class constructor function.

House = function(){
  this.floors = 4;
  this.siding = "Red";
};

Because it will be used as a constructor function and not a normal function, what we have here is the beginnings of the House class definition. This House class will then be used to make custom House object instances. Each custom House object made with this class constructor will have a floors and a siding property associated with it. By default, floors will have a value of 4 and siding, "Red."

When the House constructor is called using the new keyword, a new object is created - a new House instance. It’s the new keyword that makes the use of House a constructor and not just another function.

// House class
House = function(){
  this.floors = 4;
  this.siding = "Red";
};
// create an instance of the House class
myHouse = new House();
// check to see if the properties correctly exist
trace(myHouse.floors); // traces 4
trace(myHouse.siding); // traces "Red"

The new Keyword

The new keyword is nothing new. It’s been used a lot, probably by you and definitely in this tutorial, already. What new is, is an operator in Actionscript that initiates a constructor function call to create an instance of a new object of that constructor's class type with the definition as specified in the constructor function itself.

So far, we’ve made new Objects, new Strings, new Numbers, new Arrays and even just now, a new House. Each one of those are class constructors in Flash. Object, String, Number, Array – all constructors. House too, only House was a custom made constructor while the others are all pre-defined in Flash (residing in the _global object). Without the new keyword, they’re just functions. With the new keyword, they’re constructors creating instances of that class.

Note that in calling a constructor function with new, the this scope in the constructor call references the new instance being created and not the object calling the function. Its with this that property values and methods can be added to the new object. Also, when done, the constructor automatically returns the this object so that it can be assigned to whatever variable you are using to store the object. There is no need to have a line such as return this;
 

Instances

The point of defining a custom class is to define what will ultimately be object instances of that class – the actual working object in which you use in Actionscript to contain data and/or add functionality to your movie. These instances are equivalent to the houses in the blueprint analogy. They’re the final product resulting from the deployment of the layouts provided from the blueprints of the constructor function. You can have as many instances as you want all from the same single class constructor – as many as you need to populate your Flash movie, or neighborhood if you will. Each instance created is then said to be an "instance of the class." House instances made from the House class are instances of the House class just as arrays are instances of the Array class.

Instances are really what you’re after with OOP. The idea is to develop a framework from which you would be able to create meaningful, functional, easy to work with object instances which help you get done whatever it is you need to get done in your Flash movie.

For example, arrays are instances of array objects. Arrays help you manage and handle variables and information. You use arrays because they offer a simple linear fashion of containing variables in a list. This list then has associated with it methods that let you handle this information – methods like push, shift, reverse, sort etc.. The Array class provides the ability for you to create these helpful objects. Using OOP you are then able to create your own foundation from which you are able to create your own custom instances with similar functionality, only their functionality will be as you specify and not limited to that which has been pre-defined for you in Actionscript. Then you will be able to reap the benefits of OOP.
 

Defining Classes

Lets get back to defining the House class. Starting with the class constructor we have the following.

House = function(){
  this.floors = 4;
  this.siding = "Red";
};

This is the definition for creating house instances which, by default, will each be created with two properties, floors and siding with the values 4 and “Red” respectively. As classes go, this one’s fairly simple. In fact it’s simply constructor for creating instances that serve as containers for 2 pieces of information. Some functionality can be added to house instances by adding a simple method in the function constructor. Then, each house instance will have access to this method much like each array has access to its method push.

House = function(){
  this.floors = 4;
  this.siding = "Red";
  this.outputSiding = function(){
  trace(this.siding);
  };
};
// create an instance of the House class
myHouse = new House();
myHouse.outputSiding(); // traces "Red"

In these kinds of methods, when defined in the constructor like this (which isn’t common – something to be discussed later), be sure to assign the function to the this reference as this is the object being created. That is, after all, the object you want to use the method with. Inside the method function definition, this will also still correctly reference the new object instance as the this object is the object doing the calling of the method.

Like any other function, class constructors can also take function parameters so that you can send values into the constructor call helping you uniquely define each instance created. For example, we can make the siding of the house class customizable by passing it in as a parameter in the function call.

// class definition
House = function(siding){
  this.floors = 4;
  this.siding = siding;
  this.outputSiding = function(){
  trace(this.siding);
  };
};
// create an instance of the House class to have blue siding
myHouse = new House("Blue");

Here, myHouse has a siding value of "Blue." Note that Flash is able to distinguish the difference of the instance’s siding variable and the passed siding variable through the use of this. The this keyword indicates the difference between values in the created object and values from the local scope of the function (or the timeline even). Here, siding was used for both the argument variable and and instance’s property though it is not necessary. Feel free to use separate variable names for each if you please.

If now, say you want the siding to be optional, you could also allow for that in the constructor function definition. You would just have to check to see if a siding value was passed. If it was passed, assign the siding value to that passed siding, otherwise use a default as defined by you. This version of the House class assigns the siding of the new House instance to be the passed siding value if it was passed and is not undefined. Otherwise, it sets the siding to be "Red."

// class definition
House = function(siding){
  this.floors = 4;
  if (siding != undefined){
  this.siding = siding;
  }else{
  this.siding = "Red";
  }
  this.outputSiding = function(){
  trace(this.siding);
  };
};
// create an instance of the House class to have blue siding
myHouse = new House("Blue");
// create an instance of the House class to have red siding
myHouse = new House();

Don't, however, feel obligated to make all properties used in your constructors optional this way. Often these passed values are required. Besides, it's less work on you having to check to see whether they're defined or not to see whether they need to be assigned which value, and who needs that? For the House class constructor, we can leave siding optional, but for the floors property, we can make that a required parameter when creating a new house instance. Not every (if any) house made needs to be a whopping 4 stories high. Users of the House constructor will just need to know to make sure they specify how many floors they want their house to be when they make a new House.

// revised class definition
House = function(floors, siding){
  this.floors = floors;
  if (siding != undefined){
  this.siding = siding;
  }else{
  this.siding = "Red";
  }
  this.outputSiding = function(){
  trace(this.siding);
  };
};

And with that you have a fairly complete, though simple, class definition complete with properties and a method which will be copied into each instance of a house created.

Static Properties and Methods

Sometimes you may need to handle properties or methods in a class that is not specific to any instance of the class. These are often kept in the class constructor function object and are known as static properties and methods.

The Math object in Flash is an example of a "class" that has static properties and methods. In fact, the Math object is made solely of these. Never will you actually have a Math instance; the only time you really use Math is when you need to access its property values like Math.PI or its methods like Math.round or Math.sin. All of these are static properties and methods of the Math class. Each are defined directly to the Math constructor (though since you never make Math instances, the Math object is hardly a constructor and technically thereby not seen so much as a class). Math object methods, in their internal workings, really have no reference to or make use of a this so much. Remember, this in methods assigned in the constructor are used to reference the calling instance. In a static Math method, this would actually reference the Math object itself since Math is playing the role of an instance in that case. Because Math is a top level or global object, Math itself could be directly referenced instead of a this, thereby reducing confusion; something that could be a good idea when making your own static methods.

Maybe a better example of a class with a static method is the String class. String instances all have access to normal string methods such as charAt, substring, toLowerCase etc., but aside from those, the String constructor itself has its own method, fromCharCode. This is a method that's called directly from String itself, not an instance, and simply creates a string from a single or a series of ASCII values. Because it has no dependency on an existing string's value, it has no need to be used from one. Basically, its a normal function, it just makes a string so its kept within the String constructor object.
 

Static properties and methods can also be used to help you with your custom classes. You can have them operate on their own as the case is with the String object's fromCharCode, or you can also use them in conjunction with instances created by that class. One common use is in counting how many instances of a class were created using a static property to keep track of each instance made. All you'd need to do is make a static property in the class constructor called something like count. Then with each constructor call, increment that value to update the number of instances created. This can then be referenced directly from the class constructor in the occasion you wish to know how many instances of that class have been created. To exemplify, lets make a new class, a Fish class.
 

// define class constructor
Fish = function(type){
  this.type = type;
  Fish.count++; // increment the count variable in Fish
};
// define count in Fish to be 0 to start
Fish.count = 0;
// how many fish are there now?
trace(Fish.count); // traces 0
// make a new freshwater fish
spot = new Fish("Freshwater");
// how many fish are there now?
trace(Fish.count); // traces 1

Because count is kept in the constructor itself and not as a unique property of each fish instance, it will be increased for each fish made reflecting the total number of times the constructor is called.

In counting Fish, the Fish constructor function object was referenced directly using "Fish." There are actually 2 other ways of accessing Fish from the constructor function which could also be used. In my opinion, using the constructor name directly is the best as its the most straightforward, however, you also have the option of using arguments.callee or through using the constructor property.

Expanding on this, we set up a class to keep track of all instances created - even send them all events much in the same way all movieclip's receive the onEnterFrame event. This can be as simple as adding each instance to an array property in the class constructor whenever the constructor is called, though can also get more involved. This will be covered in greater detail later

The Constructor Property

Every time an instance is made, it receives not only what properties you define for it, but also, it automatically gets defined for it another hidden property called constructor. As its name implies, it represents the constructor function used to create that instance. Every instance of a class, no matter if its an instance of Fish, an array or even a movieclip, has a constructor property which references the constructor function used to make that instance (or at least the constructor function associated with the instance as movieclips aren't technically created exclusively with the MovieClip constructor). See the following example.

Folder = function(contents){
  this.contents = contents;
};
myDocuments = new Folder("untitled.fla");
trace(myDocuments.constructor == Folder); // traces true
myPictures = new myDocuments.constructor("clipboard.bmp");
trace(myPictures.constructor == Folder); // traces true

Since myDocuments is a Folder instance, its constructor property references the Folder constructor function. With that, as you can see, it can even be used to create another instance of its same type. The myPictures object was done in such a manner.

Shared Values Between Instances

With each constructor call when creating an instance, values from the function definition are copied into the new object instance being created. In some cases, you may have a value that is constant for every instance of an object - something that never changes and always remains the same with each instance made. In such a situation it would be favorable for each instance to not have its own copy, but rather to share one single copy thereby avoiding redundancy. You don't need to have a clock in your living room for each member of your family. Everyone can look at the same clock to see what time it is. That way you don't need to by or deal with separate clocks.

Class methods are particularly considerable in these situations. Hardly will there ever be a time where each object instance will need a unique copy of function. It would be much more efficient to have a single shared function representing a class method and not copies for each instance created. This not only avoids the redundancy in having unnecessary copies, but it also means that should you ever decide to change a method of a class, you would only need to change one shared function definition and not one for each instance. Why set all the living room clocks when you would only need to set just one?

This kind of sharing is possible using prototypes.
 

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 //--