Inheritance In Node

fgnass 16 February 2012

I usually try to avoid using inheritance in JavaScript altogether but sometimes there are situations where using a classic OO-style can make things easier.

Let’s assume we have a class Foo which we want to extend:

function Foo() {
  // constructor code
}
Foo.prototype = {
  bar: function() {
    // do something
  }
};

A common pattern is this:

function Bar() {
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.bar = function() {
  // do something else
};

In contrast to the original definition of Foo this code looks quite noisy.

Using util.inherits()

In Node.js there’s the util.inherits() function which helps us to write the same thing a little more compact and also creates a constructor property as well as a reference to the super constructor:

function Bar() {
}
util.inherits(Bar, Foo);
Bar.prototype.bar = function() {
  // do something else
};
Bar.prototype.baz = function() {
  // yet another method
};

Passing properties to Object.create()

Still we have to repeat Bar.prototype for each property we want to add. We can overcome this by passing a property descriptor to Object.create():

function Bar() {
}
Bar.prototype = Object.create(Foo.prototype, {
  bar: { value: function() {
    // do something else
  }},
  baz: { value: function() {
    // yet another method
  }}
});

Unfortunately this still looks quite noisy as we have to wrap all our properties into descriptor objects. On the other hand this syntax makes it easy to define getters or setters:

function Bar() {
}
Bar.prototype = Object.create(Foo.prototype, {
  bar: { value: function() {
    // do something else
  }},
  boo: {
    get: function() {
      return this._boo;
    },
    set: function(value) {
      this._boo = value && (''+value).toUpperCase();
    }
  }
});

Otherwise we’d have to call Object.defineProperty('boo', {...}) instead.

The get and set operators

Still this isn’t as concise as it could be. Since JavaScript 1.8.5 the language supports the get and set operators which can be used inside an object literal to define getters and setters:

function Foo() {
  // constructor code
}
Foo.prototype = {
  get boo() {
    return this._boo;
  },
  set boo(value) {
    this._boo = value && (''+value).toUpperCase();
  }
};

Now this is nice, but how can we use this approach for our subclass?

The deprecated, non-standard way

One possibility is to use the non-standard __proto__ property that allows us to change an objects prototype even after it has been created:

function Bar() {
}
Bar.prototype = {
  __proto__: Foo.prototype,
  get boo() {
    return 'Buh!';
  }
};

A standard based solution

Despite being deprecated the solution above is currently my favorite inheritance style. If you want to avoid using __proto__ for some reason you can write a helper function similar to Node’s util.inherits() that uses standard ECMAScript 5 features to achieve similar results:

function Foo() {
  // constructor code
}
Foo.prototype = {
  bar: function() {
    // do something
  }
};

function Bar() {
  // constructor code
}
util.prototype(Bar, Foo, {
  get boo() {
    return 'Buh!';
  }
});

Here is the implementation of the util.prototype function:

function prototype(ctor, superCtor, proto) {
  var props = {
    constructor: { value: ctor, writable: true, configurable: true }
  };
  Object.getOwnPropertyNames(proto).forEach(function(name) {
    props[name] = Object.getOwnPropertyDescriptor(proto, name);
  });
  ctor.prototype = Object.create(superCtor.prototype, props);
  ctor.super_ = superCtor;
}

TL;DR

The get/set operators are cool and __proto__ is your friend. If you don’t want to use it you can write a simple helper function to achive a similar result using standard ECMAScript features.