Applying properties of a base type to a subtype in JavaScript

737 views Asked by At

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);
}
2

There are 2 answers

2
T.J. Crowder On BEST 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.

0
Paul Sweatte On

There are multiple ways to do so:

//Local
function fn()
  {
  var foo = [];
  foo.toUpperCase = String(foo).toUpperCase;
  foo.push("a");
  foo.toUpperCase();
  }
fn();

//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);

//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();

//Constructor Prototype
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a");
foo.constructor();

//toString override
foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();

The built-in Error object uses the following idioms:

  • Methods

    The global Error object contains no methods of its own, however, it does inherit some methods through the prototype chain.

  • Error instances

    All Error instances and instances of non-generic errors inherit from Error.prototype. As with all constructor functions, you can use the prototype of the constructor to add properties or methods to all instances created with that constructor.

  • Error types

    Besides the generic Error constructor, there are six other core error constructors in JavaScript:

    1. EvalError

      Creates an instance representing an error that occurs regarding the global function eval().

    2. RangeError

      Creates an instance representing an error that occurs when a numeric variable or parameter is outside of its valid range.

    3. ReferenceError

      Creates an instance representing an error that occurs when de-referencing an invalid reference.

    4. SyntaxError

      Creates an instance representing a syntax error that occurs while parsing code in eval().

    5. TypeError

      Creates an instance representing an error that occurs when a variable or parameter is not of a valid type.

    6. URIError

      Creates an instance representing an error that occurs when encodeURI() or decodeURI() are passed invalid parameters.

References