JavaScript Inheritance Methods Compared

© 2011, Martin Rinehart

Regarding line count: do not use the line counts to conclude that one of these is better or worse than the others. The line counts are very much a function of coding style.

For example, if your style accepts multiple block ending braces on a single line (rather than one per line, as shown here) Flanagan's line count drops by nine; Resig's and Edwards' counts drop by six. This means line counts are all very nearly the same. Clarity of code, while harder to quantify, is a much more important concern.

Comparison of JavaScript Inheritance Methods
Eich
(no library code)
Crockford Flanagan Resig Edwards
Application Code
function A( p1, p2 ) {
    A.init( this, p1, p2 );
}
A.init = function ( inst, p1, p2 ) {
    inst.a = p1;
    inst.b = p2;
}
A.prototype.toString = function () {
    return 'A{' +
        'a=' + this.a +
        ',b=' + this.b +
    '}';
}

function B( p1, p2, p3, p4 ) {
    B.init( this, p1, p2, p3, p4 );
}
B.init = function ( inst, p1, p2, p3, p4 ) {
    A.init( inst, p1, p2 );
    inst.c = p3;
    inst.d = p4;
}
B.prototype.toString = function () {
    return 'B{' +
        A.prototype.toString.call( this ) +
        ',c=' + this.c +
        ',d=' + this.d +
    '}';
}

function C( p1, p2, p3, p4, p5, p6 ) {
    C.init( this, p1, p2, p3, p4, p5, p6 );
}
C.init = function ( inst, p1, p2,
        p3, p4, p5, p6 ) {
    B.init( inst, p1, p2, p3, p4 );
    inst.e = p5;
    inst.f = p6;
}
C.prototype.toString = function () {
    return 'C{' +
        B.prototype.toString.call( this ) +
        ',e=' + this.e +
        ',f=' + this.f +
    '}';
}
 
var o0 = {
    a: 1,
    b: 2,
    toString: function () {
        return '{' +
            'a=' + this.a +
            ',b=' + this.b +
        '}';
    }
};

var o1 = Object.create( o0 );
    o1.a = 3;
    o1.b = 4;
    o1.c = 5;
    o1.d = 6;
    o1.toString = function () {
        return '{' +
            o0 +
            ',c=' + this.c +
            ',d=' + this.d +
        '}';
    }
};

var o2 = Object.create( o1 );
    o2.a = 7;
    o2.b = 8;
    o2.c = 9;
    o2.d = 10;
    o2.e = 11;
    o2.f = 12;
    o2.toString = function () {
        return '{' +
            o1 +
            ',e=' + this.e +
            ',f=' + this.f +
        '}';
};
 
var A = Class(
    {
        name: "A",
        init: function( p0, p1 ) {
            this.a = p0;
            this.b = p1;
        },
        methods: {
            toString: function() {
                return 'A{' +
                    'a=' + this.a +
                    ',b=' + this.b +
                '}';
            }
        }
    }
);

var B = Class(
    {
        name: "B",
        extend: A,
        init: function( p0, p1, p2, p3 ) {
            this.c = p2;
            this.d = p3;
        },
        methods: {
            toString: function() {
                return 'B{' +
                    chain(this,arguments) +
                    ',c=' + this.c +
                    ',d=' + this.d +
                ")";
            },
        }
    }
);

var C = new Class(
    {
        name: "C",
        extend: B,
        init: function( p0, p1, p2,
                p3, p4, p5 ) {
            this.e = p4;
            this.f = p5;
        },
        methods: {
            toString: function() {
                return 'C{' +
                    chain(this,arguments) +
                    ',e=' + this.e +
                    ',f=' + this.f +
                '}';
            }
        }
    }
);
var A = Class.extend(
    {
        init: function ( p1, p2 ) {
            this.a = p1;
            this.b = p2;
        },
        toString: function () {
            return 'A{' +
                'a=' + this.a +
                ',b=' + this.b +
            '}';
        }
    }
);

var B = A.extend(
    {
        init: function ( p1, p2, p3, p4 ) {
            this._super( p1, p2 );
            this.c = p3;
            this.d = p4;
        },
        toString: function () {
            return 'B{' +
                this._super() +
                ',c=' + this.c +
                ',d=' + this.d +
            '}';
        }
    }
);

var C = B.extend(
    {
        init: function ( p1, p2, p3,
                p4, p5, p6 ) {
            this._super( p1, p2, p3, p4 );
            this.e = p5;
            this.f = p6;
        },
        toString: function () {
            return 'C{' +
                this._super() +
                ',e=' + this.e +
                ',f=' + this.f +
            '}';
        }
    }
);
         
var A = Base.extend(
    {
        constructor: function( p0, p1 ) {
            this.a = p0;
            this.b = p1;
        },
        toString: function () {
            return 'A{' +
                a=' + this.a +
                ',b=' + this.b +
            '}';
        }
    }
);

var B = A.extend(
    {
        constructor: function( p0, p1, p2, p3 ){
            this.base( p0, p1 );
            this.c = p2;
            this.d = p3;
        },
        toString: function () {
            return 'B{' +
                this.base() +
                ',c=' + this.c +
                ',d=' + this.d +
            '}';
        }
    }
);

var C = B.extend(
    {
        constructor: function( p0, p1, p2,
                p3, p4, p5 ){
            this.base( p0, p1, p2, p3 );
            this.e = p4;
            this.f = p5;
        },
        toString: function () {
            return 'C{' +
                this.base() +
                ',e=' + this.e +
                ',f=' + this.f +
            '}';
        }
    }
);
 
Application Length¹ 45 lines 39 lines 57 lines 48 lines 48 lines
Library Code (none) 8 lines 41 lines 58 lines 147 lines
Instance Creation
var o0 = new A( 1, 2 );
var o1 = new B( 3, 4, 5, 6 );
var o2 = new C( 7, 8, 9, 10, 11, 12 );
(none) (same as Eich)
Additional Instance Creation²
var o2x = new C( 7, 8, 9, 10, 11.1, 12.1 );
var o2x = Object.create( o2 );
    o2x.e = 11.1;
    o2x.f = 12.1;

¹Crockford would be six lines shorter if o0.a === o1.a through o1.d === o2.d.

²The new technique loses its apparent advantage if simple numeric arguments are replaced by longer arguments:

var o2x = new C( 7, 8, 9, 10, 11.1, 12.1 );

// above is shorter than:

var o2x = Object.create( o2 );
    o2x.e = 11.1;
    o2x.f = 12.1;

// but this one is longer:

var o2x = new C( 'George Washington',
    'Thomas Jefferson',
    'Theodore Roosevelt',
    'Abraham Lincoln',
    11.1, 12.1 );

Feedback: MartinRinehart at gmail dot com

# # #