JavaScript Inheritance Advice
It’s hard to find comprehensive advice online about doing class-based inheritance in JavaScript because everyone just gives their preferred solution. Here’s a rundown of what to do and what to fall back on if that’s not possible:
- Use a language that supports class-based inheritance and compiles to JavaScript. That’ll eliminate a lot of other quirks, too.
- If you can’t change languages, or you like those other quirks, the upcoming version of JavaScript supports class-based inheritance and compiles to the current version.
- If you can’t add compilation to your build, use
Object
.create
. - If you need to support a browser like IE8 that doesn’t have
Object
.create
, use a library that provides inheritance or anObject
.create
substitute. - If you can’t add a library, polyfill
Object
.create
. - If you can’t polyfill, write a helper that works like the polyfill.
- If you can’t do any of that because you’re supporting IE8 and teammates don’t want you adding dependencies, polyfilling built-ins, or writing helpers that smell like language extensions, read on.
Here’s a pattern that’s so lightweight it’s really just a convention, so easy you can use it every time you need a constructor, and so straightforward no one can claim it’s too fancy:
function(){ //scope wrapper
(
this.Book = function(words) {
this.words = words;
;
}var prot = this.Book.prototype;
.read = function() {
protreturn this.words;
;
}
.getLength = function() {
protreturn this.words.length;
;
}
.call(this); })
For any class that’s not a subclass, that’s it. You’re probably doing something similar already, and it works exactly how you’d expect:
var twoCities = new Book(
"It was the best of times, it was the worst of times . . . ");
.read();
twoCities// It was the best of times, it was the worst of times . . .
.getLength();
twoCities// 58
instanceof Book;
twoCities // true
The payoff is there’s very little you have to add – and only on the subclass side – to set up and use inheritance:
function(){
(
this.Diary = function(owner) {
//Call parent constructor.
.call(this, "Personal Diary of "+owner);
Book;
}//Set up the prototype chain, constructor, and parent access.
function Prot(){ this.constructor = Diary; }
var base = Prot.prototype = Book.prototype;
var prot = this.Diary.prototype = new Prot();
.write = function(words) {
protthis.words += "\n\n"+words;
;
}
.read = function() {
protthis.write("Today I will re-read my diary.");
return base.read.call(this);
;
}
.call(this); })
One line in the child constructor calls the parent constructor (if you need it). Two lines plus an extension to an existing line set up the prototype chain and constructor while giving easy access to overridden methods. All of it’s done with short, flat, straight-line code.
It’s so clear, it almost makes the requirements it’s fulfilling seem sensible: The prototype’s prototype has to be the parent .prototype
, and the prototype’s .constructor
has to be the child constructor.
Now you have class-based single inheritance:
var secretDiary = new Diary("Brian");
.write("Wrote a blog entry about JavaScript today.");
secretDiary.read();
secretDiary// Personal Diary of Brian
//
// Wrote a blog entry about JavaScript today.
//
// Today I will re-read my diary.
.getLength();
secretDiary// 99
instanceof Book;
secretDiary // true
instanceof Diary;
secretDiary // true
.constructor == Diary;
secretDiary// true