Prototype vs Class Inheritance in YUI 3

0

Posted on : 01/07/2010 | By : Jimmy Vu | In : Development News, Solution

As I mentioned in the post YUI 3.0 – Changes From the Root, YUI 3 is a radical evolvement of the framework. One of the most interesting features it provides with is about much better support for OOP.

YUI 3 supports two inheritance patterns via object prototype and “class”. Let’s examine the differences and advantages of each pattern.

Prototypal Inheritance in YUI 3

Suggested by Douglas Crockford, prototypal inheritance pattern is to deal with objects, i.e. objects inherit from objects. YUI 3 supports prototypal inheritance from its core; it means you can utilize the pattern by including the seed file only:

<script type="text/javascript" 
    src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>

Now, for example, we have an object named animal:

var animal = {
    name: "Animal",
    level: "top",
    say: function() {
        return "I am an " + this.name + " at " + this.level + " level.";
    }
};
 
alert(animal.say()); // I am an Animal at top level.

And you want to create an elephant object that is an inheritance of animal. It’s so easy to do:

var elephant = Y.Object(animal);

Of course, you’ll need to modify the newly-born creature to make it a true elephant by overriding its parent properties and adding some new ones:

// override an animal’s property
elephant.level = "second";
 
// add elephant’s own properties
elephant.trunk = 1;
elephant.tusks = 2;

However if you want the elephant to say more about its own belongings, you’ll have to redefine say method completely.

elephant.say = function(){
    return "I am an " + this.name + " at " + this.level + " level."
        + " I have " + this.trunk + " trunk and " + this.tusks + " tusks.";
};
 
alert(elephant.say()); // I am an Animal at second level. I have 1 trunk and 2 tusks.

I think this pattern is quite easy to understand but before going forward to the next one, here are what we learn from it:

  1. We can create a new object that inherits all the properties and methods from an existing object.
  2. We can customize the new object by overwriting some/all of the members or adding new ones.
  3. The dark part is an overwritten property has no way to reference its parent’s property.

    Note: In this pattern, the child’s properties do not really overwrite its parent’s ones but they just take higher precedence. So if we delete a child’s method, the parent’s one will be back magically. For example:

    delete elephant.say;
    alert(elephant.say()); // I am an Animal at second level.

“Class” Inheritance in YUI 3

Yes, I know there are no true classes in JavaScript, however we can make constructor functions act like classes for OOP (you can read more from the book Object-Oriented JavaScript by Stoyan Stefanov).

Note: From now on, for easier to understand the pattern, I’ll call all constructor functions (that are capitalized in examples) classes; don’t be confused.

First, we’ll mimic above example by creating  Animal and Elephant classes as follows:

// parent class
function Animal(){
    this.name = "Animal";	
}
// parent’s properties
Animal.prototype.getName = function(){
    return this.name;
};
Animal.prototype.setName = function(name){
    this.name = name;
};
 
// child class
function Elephant(){}

YUI 3 supports class inheritance via oop module and because this is used widely by almost all other modules, you’ll rarely have to include it explicitly. However, for testing, just call Y.extend() method within oop’s scope (that let Elephant inherit Animal as you can guess):

YUI().use('oop', function(Y){
    Y.extend(Elephant, Animal);
 
    // test code here
    // ...
}

Next we’ll do some tests:

// create an object of Elephant
var jumbo = new Elephant();
 
alert(typeof(jumbo.name)); // undefined
alert(typeof(jumbo.getName)); // function
 
// set name for the Elephant object			
jumbo.setName("Jumbo");
alert(jumbo.getName()); // Jumbo

You can see from the example, jumbo object which is an instance of Elephant class only inherit members of the prototype, not “private” members from parent’s class and it is considered a good practice to leave all instance-specific properties as private properties and to add all the public functionality to the prototype.

Interestingly we can add some new properties with default values to child class via arguments of Y.extend(), for example, to add trunk and tusks to Elephant class:

// create an object of Elephant “class”
var jumbo = new Elephant();
 
alert(typeof(jumbo.name)); // undefined
alert(typeof(jumbo.getName)); // function
 
// set name for the elephant				
jumbo.setName("Jumbo");
alert(jumbo.getName()); // Jumbo

Last but not least, class inheritance has very powerful feature: superclass access. To see how it works, we’ll add a method to Animal class to let it say something.

// parent class
function Animal(){}
 
// parent’s method
Animal.prototype.say = function(){
    return "I am an animal.";
};

Then, we’ll overwrite say method in Elephant class, yet still be able to keep what Animal can say about.

Y.extend(Elephant, Animal, {trunk: 1, tusks: 2});
 
Elephant.prototype.say = function(){
    	  return Elephant.superclass.say() + 
		" I have " + this.trunk + " trunk and " + this.tusks + " tusks.";
};
 
// test
jumbo = new Elephant();
alert(jumbo.say()); // I am an animal. I have 1 trunk and 2 tusks.

In summary, “class” inheritance pattern in YUI 3 is more powerful than prototypal counterpart though harder to get it full, here are some important points:

  1. YUI 3 allows us to implement inheritance at (pseudo) class level in JavaScript.
  2. Inherited classes cannot directly access to parent’s own members, children only inherit prototype members by default.

    Note: Well, it is possible to inherit parent’s own properties by initializing the parent constructor from the child (but it is not always a good OOP practice). See example:

    // parent class
    function Animal(){
        this.name = "Animal";	
    }
    // child class
    function Elephant() {
        // initialize the parent using the child as "this"
        Elephant.superclass.constructor.apply(this, arguments);
    }
     
    Y.extend(Elephant, Animal);
     
    // test
    jumbo = new Elephant();
    alert(jumbo.name); // Animal
  3. You can gain access to the parent’s overridden methods via superclass.

Conclusion

Code reuse is considered as the most confusing part of JavaScript for it lacks robust OOP features that many modern programming languages provide by default. YUI 3 with the two inheritance patterns we’ve gone through is trying to fill the gap.

Prototypal inheritance is easier to understand but limit in object inheritance only. To get full OO support in YUI 3, it is advisable to study “class” inheritance pattern provided by the framework.

Related Reading:

Share this :

  • Stumble upon
  • twitter

Comments are closed.