I have one constructor function, which acts as a superclass:
Bla = function(a){this.a = a;}
I prototype it to include a simple method:
Bla.prototype.f = function(){console.log("f");
And now new Bla(1).f(); will log “f” in the console. But, lets say that I need a subclass that inherits from Bla:
Bla2 = function(a)
{
this.base = Bla;
this.base();
}
x = new Bla2(5);
Now, as expected, x.a gives me 5. But, x.f is undefined! Seems like Bla2 didn’t inherit it from the Bla class! Why is this happening and how do I correct it?
Right. You haven’t done anything to hook up inheritance there, you’ve just created a member of
Bla2calledbasewhich is aBlainstance.baseis not a special identifier in JavaScript.The typical way to set up inheritance in JavaScript looks like this:
…where
Object.createis 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 ofObject.create; see below.) And then you use it:Live example | source
In older code you sometimes see the
Derived.prototypeset up like this instead:…but there’s a problem with doing it that way:
Basemay do per-instance initialization which isn’t appropriate for the entirety ofDerivedto inherit. It may even require arguments (as ourBasedoes; what would we pass forx?). By instead makingDerived.prototypejust be a new object backed by theBase.prototype, we get the correct stuff. Then we callBasefrom withinDerivedto 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 ownLineage.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:Then instead of
you’d do:
Of course, you can do more to automate hooking things up — which is all
Lineagebasically does.…and finally: Above I’ve used anonymous functions for simplicity, e.g.:
…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:…or something like that. Live copy | source