Ben Aston Ben Aston - 4 days ago 5
Javascript Question

Applying properties of a base type to a subtype in JavaScript

I would like to include the properties and initialization logic from a "base" type into a "sub" type in JavaScript. Is the following idiomatic?

function Base(arg1) {
this.foo = arg1.foo;
}

function Sub(arg1) {
//Initialize using the base ctor...
Base.call(this, arg1);
}

Answer

Yes (but just this.foo = arg1 in the Base, not arg1.foo), that's the typical way you set up a base/derived relationship with JavaScript's prototypical inheritance and constructor functions. Here's the complete pattern:

function Base(arg1) {
  this.foo = arg1;
}
Base.prototype.doSomething = function() {
  snippet.log("doSomething says foo is " + this.foo);
};

function Sub(arg1) {
  //Initialize using the base ctor...
  Base.call(this, arg1);
}
Sub.prototype = Object.create(Base.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.doSomethingElse = function() {
  snippet.log("doSomethingElse says foo is " + this.foo);
};

// Usage
var s = new Sub('bar');
snippet.log("s.foo = " + s.foo);
s.doSomething();
s.doSomethingElse();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

I have a script, Lineage, that makes it more declarative, encourages private resources, and makes calls to parent "class" methods easier. But that script will be obsoleted by ES6's classes, which despite being called classes are still prototypical in nature. (And there are transpilers for ES6's class syntax that generate ES5 code, so you can use the new syntax now, it just means you need a build step before using the result.)

If you need to support really old browsers (like IE8) that don't have Object.create, you can shim the one-argument version of it used above:

if (!Object.create) {
    Object.create = function(proto, props) {
        if (typeof props !== "undefined") {
            throw "The second argument of Object.create cannot be shimmed.";
        }
        function ctor() { }
        ctor.prototype = proto;
        return new ctor();
     };
}

Note that constructor functions are just one way you can use prototypical inheritance in JavaScript, not the only way. But if you're using constructor functions, that's the pattern.

Comments