Javascript: Inheritance

Contents

  1. Introduction
  2. Classical Inheritance
  3. Classical Inheritance with helpers
  4. Prototypal Inheritance
  5. Prototypal Inheritance with helpers
  6. Conclusion
  7. Resources

1. Introduction

For those who build complex web application, it might be wise to practice Object Oriented Programming (OOP), apply design patterns when possible and use one of the MVC frameworks available. OOP is all about modeling complexity and it makes your application scale well, but remember it is definitely not the holy grail. Code bloat is always lurking around the corner, and not to forget my favorite the ‘Lost in space syndrome‘; everything happens somewhere else. And to top all this off, javascript doesn’t even have classes, because it is a prototype based language, meaning the whole OO principle works different.
In this article I will show how Classical -and Prototypal Inheritance work and how it can be made easy and more powerful using my Javascript Inhertiance Library (JIL).

2. Classical Inheritance

In classical inheritance you use the ‘new’ keyword, to treat a function as a constructor. Javascript functions double as object and constructor. Its the prototype property of this function which acts as a template for all objects it creates.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Bar = (function($) {
    var msg ; // private variable
    function Bar(input) { msg = input };
    
    Bar.prototype.toString = function(){ return this.constructor.name; }; 
    Bar.prototype.getMsg = function() {
        return msg ;
    }
    return Bar ;
})(jQuery) ;

Above I’ve applied the Module Pattern, a perfect way to simulate classes. It is considered a good practice to provide all external dependencies of a class as its arguments (like I’ve done here with jQuery). So, to let class Foo inherit from Bar do

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Foo = (function(parent) {
    function Foo(input){
        parent.apply(this, arguments) ; // call parent constructor
    } 
    
    Foo.prototype = new parent() ;      // inherit from parent.prototype
    Foo.prototype.constructor = Foo ;   // fix instanceof
    Foo.prototype.getMsg = function() {
        return 'Foo\'s  ' + parent.prototype.getMsg.call(this) ; // call overriden method
    }
    return Foo ;
})(Bar) ;

(example on jsfiddle)

As you can see, it requires some prototype magic, but at the end you have classical inheritance up and running.

3. Classical Inheritance with helpers

All this prototype juggling from the previous section is nice, but if you’re already dealing with complex matter, it will probably not make you more productive. So to simplify classical inheritance, copy the JIL code into your project and the Foo class can be transformed into

1
2
3
4
5
6
7
8
9
var Foo = Bar.$augment( 
    function Foo(input) {      // constructor
        this.$super(input);
    }, 
    {                          // the prototype properties
        getMsg: function() {
            return 'Foo\'s  ' + this.$super() ;
    }
) ;

(example on jsfiddle)
Unfortunately, the new keyword has two problems. If you omit it by accident, the code is still valid, and the function in question is not called in its god-mode, and the bug-hunt that will follow can take a lot of time. The second issue is that you cannot use any of the functional features like apply or call. The library solves this issue and introduces the $new functions

1
2
var arr = ['secret', 10] ;
var foo = Foo.$new.apply(arr) ;

4. Prototypal Inheritance

The new keyword and the prototype property try to fix the gap between its prototypal nature and classical inheritance, but still this whole implementation feels a little bit clumsy. With prototypal inheritance, a form of object-oriented code reuse, objects are created using other objects:

1
2
3
4
5
6
7
8
9















var o1 = { a: 1 }
    , o2 = Object.create(o1) 
    , o3 = Object.create(o2) ;

o2.b = 2 ;
console.log(o3.a + ' and ' + o3.b) ; // --> 1 and 2
console.log(o3.hasOwnProperty('b') ; // --> false
console.log(Object.getPrototypeOf(o3).hasOwnProperty('b')) ; // --> true
console.dir(o3)
console.dir

Internally objects keep a reference with their creator/prototype ( __proto__ ), which is known as the prototype chain

5. Prototypal Inheritance with helpers

This looks a lot easier than what we saw with Classical Inheritance, but calling overridden methods is still equally painful. Also note that there is no default constructor anymore. The Bar-Foo example from above can be rewritten as follows

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Bar = Object.$augment(
    (
        function($) {    // closure
            var msg ;    // private variable
            return {
                cname: 'Bar'   
                , constructor: function(input) { msg = input }
                , toString: function(){ return this.cname; }
                , getMsg: function() { return msg ; }
           } ;
        }
    )(jQuery) 
) ;     

var Foo = Bar.$augment( {
        cname: 'Foo',
        constructor: function constructor(input) { this.$super(input); },
        getMsg: function getMsg() {
            return 'Foo\'s  ' + this.$super() ;
        }
    }       
) ;

(example on jsfiddle)

If performance is crucial, it will help to define named functions instead of anonymous functions.

6. Conclusion

In this article I have shown that Prototypal Inheritance suits javascript very well. Classical inheritance on the other hand, uses some mechanisms to simulate the whole thing. Adding to that the issues with the new keyword, its probably better to opt for Prototypal Inheritance. On the other hand, if you are used to classical inheritance, it is probably easier to get started with classical variant. For both applies that JIL really simplifies the whole process.

7. Resources