Make your own free website on Tripod.com

Constructor and New


Create object with or without constructor

There are two ways to create objects. One is through object initializer:
a={x:3,y:4};

The other is through constructor with the keyword "new".
b=new Object();
b.x=3;
b.y=4;


a and b are nearly the same in functionality. However, b has a hidden property:__constructor__;
trace(a.__constructor__); // the output is "undefined"
trace(b.__constructor__);// the output is [function Object];

Lets see how to use Function to create an object:

function createBall(x,y){
    var temp={};
    temp.x=x;
    temp.y=y;
    temp.move=function(){this.x+=3;}
    return temp;
}
ball1=createBall();

Here we create a temporary object with properties and methods, then return out the reference. We did not created this object by "new". Our object does not have __constructor__ property. We do not refer this object as "instance".

Now lets use constructor:

function Ball(x,y){
    this.x=x;
    this.y=y;
    this.move=function(){this.x+=3;}
}
ball2=new Ball();

Here we use "new". The function is a "constructor" now. And we can see how the syntax of constructor is different from Function. It uses "this" vigorously. There is no temporary object nor it return any reference out.  The object has a __constructor__ property pointing to the constructor "Ball". We say this object is an "instance" of Ball.

What is constructor and new ?

The keyword "new" is always followed by a constructor call to create a new instance. It has no other usage.


Empty constructor

We see many constructors that contain no scripts in the body.

Circle=function(){
}
Circle.prototype.radius=10;
Circle.prototype.getArea=function(){return Math.PI*this.radius*this.radius;}

circle1=new Circle();
area_of_circle1=circle1.getArea();

What jobs does this empty constructor serve ?

Two things are done by combination with "new". One is create a new instance with __constructor__ property set to this function "Circle". The second thing is assign the prototype of the constructor to be the __proto__ of the new object. Usually the third thing is to initiate some properties into the local of the instance, such as  this.x=5, this.name=.... etc, but here the constructor is empty, so it does not initiate anything to local.

I will discuss the __proto__ things later. Anyway, the new object is equipped with all the properties shown in constructor.prototype. So our object can execute the method "getArea()";

Here I would explain the scripts first.

First we "define" a function/constructor. Any scripts written in the body of the constructor are just "defined" but not "executed". It will be excuted when we say "new - constructor" but not now.

Next, we make the prototype grow up. We create many methods or properties and "assign" to the constructor.prototype. It is "assignment".

Then we use new-constructor to create a new object with __proto__ set to constructor.prototype. Here, the script in the body of the constructor is "executed".

Note: Assignment of __proto__ happens first. All the methods and properties in the prototype are available for scripting in the constructor. If the prototype over-ride any methods inherited frome superClass, the constructor executes the updated version.


Why do we intend to make empty constructor ?

If we are going to create only one such object, we dont bother creating a constructor.

When we define a constructor, we intend to create a Class. That means we intend to create many objects with similar properties. Many instances of that Class.

Example 1:

Circle=function(){
    this.radius=10;
    this.getArea=function(){return Math.PI*this.radius*this.radius;}
}

circle1=new Circle();
circle2=new Circle();
circle3=new Circle();

By this, circle1, circle2 and circle3 will have their own property - "radius"  and method - "getArea". The getArea method with the body script is "defined by constructor" when instance is constructed. Each circle instance occupies a local memory block similar to what we see in the construct block of this web page.

Lets modify a little bit:

Example 2:

function getArea(){return Math.PI*this.radius*this.radius;}

Circle=function(){
    this.radius=10;
    this.getArea=getArea;
}

circle1=new Circle();
circle2=new Circle();
circle3=new Circle();

By this, circle1, circle2 and circle3 will have their own property - "radius"  and method - "getArea"; For each, the getArea method is just defined as a reference to some already defined function. Function body is not stored in the instance. Each circle instance occupies a local memory block much less than the first exmaple.

Lets back to the example codes in the begining of this session:

Circle=function(){
}
Circle.prototype.radius=10;
Circle.prototype.getArea=function(){return 2*Math.PI*this.radius*this.radius;}

circle1=new Circle();
circle2=new Circle();
circle3=new Circle();

Here we take advantage of prototype. We put all these properties and methods in a single prototype object. Each circle instance occupies nearly nothing as local memory block and still have the properties "radius" and methods "getArea";

This is marked improvement in saving memory.

So, we see many examples of OOP where the properties and methods are shift to prototype and the constructor was intended to be blank.


Can we shift all properties from constructor to prototype ?
What if the property is an object or array?

Circle=function(){
    this.center={x:0,y:0};
    this.history=[];
}

circle1=new Circle();
circle2=new Circle();

circle1.center.x=10;
circle1.history.push(10);

circle2.center.x=-10;
circle2.history.push(-10);

Constructor creates properties in "local", that is unique for that instance. Prototype creates properties that will be shared.

The above example will make circle1.center to be {x:5,y:0} and circle1.history to be [10]; The circle2 will have different center and history.

Lets move it to prototype:

Circle=function(){
}
Circle.prototype.center={x:0,y:0}
Circle.prototype.history=[];

circle1=new Circle();
circle2=new Circle();

circle1.center.x=10;
circle1.history.push(10);

circle2.center.x=-10;
circle2.history.push(-10);

Now, the center and history are moved to "shared" part, the prototype. All these instances share the same center and history. circle1 set the center.x to be 10, but it gets re-set to be -10 by the circle2. The history array gets two push commands and will contain two elements [10,-10];

This happens because properties stores a reference of object. We are changing the object it refers. We did not change the reference. This does not happens when properties are "primitive values" . Primitive values such as integer or string are not accessed by reference.


Destructor

In some other language, we will write "destructor" to clean some useless memory. Flash does not implement this. 

I have seen some script over-rides the removeMovieClip method to do some cleaning job. For example: when the movieclip calls removeMovieClip(), it calls removeListener.

Although the movieclip may be unloaded by many method, it is a good habit to do so. 


Conclusiion: What should be set in constructor ?

What should be set in constructor and what should be put to the prototye depends on the plan. Usually the shared, read-only properties such as constants are put in the prototype. If the values of property are unique to each instance, then we set it in the constructor.

However, we can not say the rule is "absolute".