Class Simulations



Class simulations are comprehensive use of concepts mentioned in the previous articles. Take class encapsulation and inheritance for examples. Basically, you can implement them as follows:
function Circle(x, y, r) {
    // states of an instance
    this.x = x;
    this.y = y;
    this.r = r;
}

// similar to the static method of the Java class
Circle.PI = 3.14159;

// shared instance methods are defined on the prototype object
Circle.prototype.area = function() {
    return this.r * this.r * Circle.PI;
};
Circle.prototype.toString = function() {
    var text = [];
    for(var p in this) {
        if(typeof this[p] != 'function') {
            text.push(p + ':' + this[p]);
        }
    }
    return '[' + text.join() + ']';
};

function Cylinder(x, y, r, h) {
    // call the constructor of the parent class
    Circle.call(this, x, y, r);
    this.h = h;
}

// prototype-based inheritance
Cylinder.prototype = new Circle();

/*
 *  set the constructor function Cylinder
 *  as the constructor property of prototype

 */
Cylinder.prototype.constructor = Cylinder;

/*
 *  the following properties will be created
 *  when creating an instance with the new operator,
 *  so currently they are not necessary

 */
delete Cylinder.prototype.x;
delete Cylinder.prototype.y;
delete Cylinder.prototype.r;

// shared instance methods are defined on the prototype
Cylinder.prototype.volumn = function() {
    return this.area() * this.h;
};

You can encapsulate the above code flow to look more like a class definition. For instance, you can encapsulate the process of creating a class.
var Class = {};
Class.create = function(methods) {
    var Clz = methods.initialize;
    for(var mth in methods) {
        if(mth != 'initialize') {
            Clz.prototype[mth] = methods[mth];
        }
    }
    return Clz;
};

Then you can use as follows:
var Circle = Class.create({
    // similar to the constructor of the class
    initialize : function(x, y, r) {
        this.x = x;
        this.y = y;
        this.r = r;
    },
    area : function() {
        return Math.PI * Math.pow(this.r, 2);
    },
    toString : function() {
        var text = [];
        for(var p in this) {
            if(typeof this[p] != 'function') {
                text.push(p + ':' + this[p]);
            }
        }
        return '[' + text.join() + ']';
    }
}
);
var circle = new Circle(10, 10, 5);


If you want to encapsulate the process of inheriting a class, you can do as follows:
Class.extend = function(Superclz, methods) {
    var Subclz = this.create(methods);
    var subproto = Subclz.prototype;
    Subclz.prototype = new Superclz();
    for(var p in Subclz.prototype) {
        if(Subclz.prototype.hasOwnProperty(p)) {
            delete Subclz.prototype[p];
        }
    }
    Subclz.prototype.constructor = Subclz;
    for(var p in subproto) {
        Subclz.prototype[p] = subproto[p];
    }
    return Subclz;
};
For example, you can do as follows to inherit the Circle class defined in the above code.
var Cylinder = Class.extend(Circle, {
    initialize : function(x, y, r, h) {
        Circle.call(this, x, y, r);
        this.h = h;
    },
    volumn : function() {
        return this.area() * this.h;
    }
}
);
var cylinder = new Cylinder(10, 10, 5, 15);

The above code only shows basic ideas of how to simulate class-based features. In fact, there are many design approaches depending on the extent or style of simulation.