Thursday, March 29, 2012

What I learned from THREE.js: calling parent methods

Three.js is awesome, it simplifies working with WebGL, and is a great source for JavaScript ideas. This article presents another idea I came across while working THREE.js source; applying a parent class' constructor to an inheriting class. To do this the parent constructor is invoked using apply or call.

var ClassA = function(){};

//ClassB inherits ClassA
var ClassB = function(){
    ClassA.call(this); //run parent constructor on this object
};
ClassB.prototype = new ClassA(); //inherit parent methods

The example above does call the parent constructor, but doesn't accomplish anything. Instance methods and properties are added to the prototype on the last line of the block. Calling the parent constructor is only useful when there are parameters. A simple example is extending DataModel object that manipulate and hold information pulled from a database.

//assume data has been converted to a javascript object
var DataModel = function(data){
    data = data || {}; //make sure data is a valid object
    this.id = data.id || ""; //stores id on the instance
};

//person inherits from data model
var Person = function(data){
    DataModel.call(this, data); //get a valid id

    data = data || {}; //make sure data is a valid object
    this.firstName = data.firstName || ""; //stores id on the instance
    this.lastName = data.lastName || ""; //stores id on the instance
}
Person.prototype = new DataModel();

Now any class that extends DataModel will have some defined value for id. Similarly an extension of Person would have a defined value for firstName and lastName.

You can take this concept even further. It can be used when overriding inherited methods as well. Note: this will not work as expected if using THREE.js' technique of defining instance methods as explained in the preceding THREE.js article.

In this next block, the DataModel and Person classes implement a toObject function, that returns the instance property values. The DataModel handles the the id property, while the Person handles the first and lastName properties.

//returns the 
DataModel.prototype.toObj = function(){
    var obj;
    obj.id = this.id;
    return obj;
}

//overrides DataModel toObj.
Person.prototype.toObj = function(){
    var obj = DataModel.prototype.call(this); //get object with id
    obj.firstName = this.firstName;
    obj.lastName = this.lastName;
    return obj;
}

In retrospect, this idea seems obvious. After all, this article demonstrates how to use call or apply to implement private methods, and the idea presented in this post simply uses the same concept on parent methods.

No comments:

Post a Comment