In the previous post, I started talking about how we can enhance our OO Javascript code by using ATLAS. I ended the previous post by referencing that the registerClass is really important and if you miss calling that the “ATLAS OO” code won’t work properly. So what does it do? Before going into that, I must talk about two methods: registerAbstractClass and registerSealedClass. As you expect, registerAbstractClass registers an abstract class (which shouldn’t be directly instantiated); on the other hand, the registerSealedClass is used to create a sealed class.
Internally, each of the previous methods initializes a field maintained by the object that represents the class. Currently, the platform only enforces sealed classes (ie, though you shouldn’t create an abstract class, you can do that; however, if you try to use a sealed class as the base of another class, it’s like you didn’t set a base class – ie, the base constructor won’t be called during initialization).
Internally, the registerXXX methods are responsible for initializing several fields which are maintained by the object that describes the class. Besides setting the type name (internal field _typeName), it initializes the name of the base classes (maintained in __astrPendingInheritances array) and a list of interfaces implemented by the current class (kept in the _interfaces properties). As we’ll see, these fields are important during instantiation time. Before delving into that, it’s time to see how we can create a new derived class. In this case, we’ll create a Student derived class (which we’ll call UniStudent):
LA.UniStudent = function( age, name, uni ){
LA.UniStudent.initializeBase( this, [age, name] );
var _uni = uni;
this.get_uni = function(){ return _uni; }
this.set_uni = function( value ){ _uni = value; }
}
LA.UniStudent.registerSealedClass( "LA.UniStudent", LA.Student );
The first thing to note is that calling the initializeBase method must be the first thing a derived class constructor should do. Then we go along and add more fields and members to our class. Finally, we still do need to register the class (and in this case, we’re creating a sealed class).
The initialize method is the main responsible for creating the inheritance illusion introduced by ATLAS. You see, instead of relying in the use of the prototype type, the team uses some fancy tricks which rely on the apply method of the Function Javascript object. What happens during initialization is that the base class (which as we saw, is represented by a method) will be applied to the current instance with code similar to this (this is the most important line):
this.bases[ i ].apply(p_objInstance, p_objArgs);
When ATLAS reaches this phase of initialization, it already has the bases property correctly filled up (with a pointer to the constructor of the base class) and what the previous line of code is doing is applying the constructor to the current instance that is being created (and passing some args maintained in the p_objArgs parameter – which, btw, is the array which is being sent to the initializeBase method called from the base class). In practice, this means that after calling the previous line, our new object will have all the fields and members defined by the base class appended to them as if they’ve been set in the derived class. All this happens when you call the initializeBase method (and do take in mind that this will propagate through all the classes in the hierarchy).
This is really cool and solves most of the problems associated with traditional inheritance offered by Javascript.
Using a derived class is really simple: you start by creating a new instance and then you access the properties of that object. Here’s a quick example on how that can be achieved:
var std = new LA.UniStudent( 30, "Luis", "UMa" );
alert( std.get_name() + " - " + std.get_age()+ " - " + std.get_uni() );
On the next post we’ll see how we can create and use interfaces.