Thursday, January 2, 2014

How to Extend a Javascript Pseudo Class

I recently built an HTML 5 Canvas project using CreateJS which I ended up really enjoying since I spent a few years of my career building Adobe Flash apps. I remember thinking "Why doesn't Adobe take Flash/ActionScript 3 and write a version that works with HTML5 Canvas/Javascript?" we'll they did (sort of). In a future post, I hope to write more about that project, but this post is more on how to extend JavaScript classes since that's what you do with the CreateJS framework.

We all use jQuery and that's awesome, so you don't really need to worry about JavaScript pseudo classes, but once in a while you may find yourself writing plain JavaScript (or at least using a different framework than jQuery). Since JavaScript's biggest downfall is that there isn't a built in class structure we are left with pseudo classes.

This is all explained very well in David Shariff's blog that can be found here:
http://davidshariff.com/blog/javascript-inheritance-patterns/
So, I'm just going to show how to used the Pseudoclassical pattern like I did with CreateJS.

In CreateJS, you have a bunch of core JavaScript pseudo classes already available to you, and all you need to do is extend the correct ones for you app's needs. This functionality can be used without CreateJS since it's all basic javascript, for example:
(function() {
    var Car = function(color)
    {
        this._wheels = 4;
        this._condition = 'good';

        //this will serve as our 'super()' method
        this.initialize(color);
    }
    Car.prototype.initialize = function(color)
    {
        this._color = color;
        ...
    }
    Car.prototype.drive = function(speed)
    {
        ...
    }
    //setup a namespace if you want
    window.Car = Car;
}());

//create a car and drive
var myCar = new Car(#bada55);
myCar.drive(90);


Now we end up with the class 'Car' that we can re-use in our JavaScript application. Now, we have a 'Truck' object that is a lot like car so we should extend the 'Car' class to reduce code. How do we do this with Javascript since you can't just say:
function Truck() extends Car()
{
    //call car constructor
    super(color);

    //set variables for truck
    this._type = 'pickup';
} 

This is where we use the prototype attribute, but we can't just say Truck.prototype = Car.prototype because now any new methods on Truck will be passed back to Car. The trick is to pass a unique reference for a Car to a temp object and then add to it. So, now the 'Truck' class ends up looking like this:
(function() {
    var Truck = function(color)
    {
        this._type = 'pickup';

        this.initialize(color);
    }
    //here we are creating a Car and passing a unique reference 
    //to the var 'tmp'
    var tmp = Truck.prototype = new Car();

    //now we need to save a reference to the parent 
    //initialize method (like calling 'super()' in other languages)
    Truck.prototype.Car_initialize = tmp.initialize;
    
    //now create a initialize() method for truck that calls 
    //Cars initialize() method
    Truck.prototype.initialize = function(color) 
    {
        this.Car_initialize(color);
        ...
    };
    
    //add a new method only to the 'Truck' class
    Truck.prototype.tow = function(weight)
    {
        ...
    }
    //setup a namespace if you want
    window.Truck = Truck;
}());

I thought this was slick, and you can even move this into a method like so:
var classExtend = function(childClass, parentClass)
{
    var tmpObj = function() { };
    tmpObj.prototype = new parentClass();
    childClass.prototype = new tmpObj();
    childClass.prototype.constructor = childClass;
};

var Car = function()
{
    this._type = 'car';
    ...
}
var Truck = function()
{
    this._type = 'truck';
    ...
}
Truck.prototype.tow = function(weight) { }

//extend the car class
classExtend(Truck, Car);

No comments:

Post a Comment