Objects don’t inherit prototyped functions

Seems like Bla2 didn’t inherit it from the Bla class!

Right. You haven’t done anything to hook up inheritance there, you’ve just created a member of Bla2 called base which is a Bla instance. base is not a special identifier in JavaScript.

The typical way to set up inheritance in JavaScript looks like this:

// The base constructor function
function Base(x) {
    // Base per-instance init
    this.x = x;
}

// An example Base function
Base.prototype.foo = function() {
    console.log("I'm Base#foo, x = " + this.x);
};

// The Derived constructor function
function Derived(x, y) {
    // Normally you need to call `Base` as it may have per-instance
    // initialization it needs to do. You need to do it such that
    // within the call, `this` refers to the current `this`, so you
    // use `Function#call` or `Function#apply` as appropriate.
    Base.call(this, x);

    // Derived per-instance init
    this.y = y;
}

// Make the Derived.prototype be a new object backed up by the
// Base.prototype.    
Derived.prototype = Object.create(Base.prototype);

// Fix up the 'constructor' property
Derived.prototype.constructor = Derived;

// Add any Derived functions
Derived.prototype.bar = function() {
    console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
};

…where Object.create is from ES5, but it’s one of the things that can easily be mostly shimmed. (Or you can use a function that only does the bare minimum without trying to do all of Object.create; see below.) And then you use it:

var d = new Derived(4, 2);
d.foo(); // "I'm Base#foo, x = 4"
d.bar(); // "I'm Derived#bar, x = 4, y = 2"

Live example | source

In older code you sometimes see the Derived.prototype set up like this instead:

Derived.prototype = new Base();

…but there’s a problem with doing it that way: Base may do per-instance initialization which isn’t appropriate for the entirety of Derived to inherit. It may even require arguments (as our Base does; what would we pass for x?). By instead making Derived.prototype just be a new object backed by the Base.prototype, we get the correct stuff. Then we call Base from within Derived to get per-instance init.

The above is very basic and as you can see involves a number of steps. It also does little or nothing to make “supercalls” easy and highly-maintainable. That’s why you see so many “inheritance” scripts out there, like Prototype’s Class, Dean Edwards’ Base2, or (cough) my own Lineage.


If you can’t rely on having ES5 features in your environment, and don’t want to include a shim that does the basics of Object.create, you can just use this function in its place:

function simpleCreate(proto) {
    function Ctor() {
    }
    ctor.prototype = proto;
    return new Ctor();
}

Then instead of

Derived.prototype = Object.create(Base.prototype);

you’d do:

Derived.prototype = simpleCreate(Base.prototype);

Of course, you can do more to automate hooking things up — which is all Lineage basically does.


…and finally: Above I’ve used anonymous functions for simplicity, e.g.:

Base.prototype.foo = function() {
    // ...
};

…but I don’t do that in my real code, because I like to help my tools help me. So I tend to use the module pattern around each “class” (constructor function and associated prototype) and use function declarations (since I do work for the web, and IE7 and IE8 still have problems with named function expressions. So if I weren’t using Lineage, I’d do the above like this:

// Base
(function(target) {
    // Base constructor
    target.Base = Base;
    function Base(x) {
        // Base per-instance init
        this.x = x;
    }

    // An example Base function
    Base.prototype.foo = Base$foo;
    function Base$foo() {
        console.log("I'm Base#foo, x = " + this.x);
    }
})(window);

// Derived
(function(target, base) {
    // The Derived constructor function
    target.Derived = Derived;
    function Derived(x, y) {
        // Init base
        base.call(this, x);

        // Derived per-instance init
        this.y = y;
    }

    // Make the Derived.prototype be a new object backed up by the
    // Base.prototype.    
    Derived.prototype = Object.create(base.prototype);

    // Fix up the 'constructor' property
    Derived.prototype.constructor = Derived;

    // Add any Derived functions
    Derived.prototype.bar = Derived$bar;
    function Derived$bar() {
        console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
    }
})(window, Base);

…or something like that. Live copy | source

Leave a Comment