Prototyal Inheritance in JavaScript (continued)

Note: This is a continuation of my last post

The Problem (Naive Approaches)

Now that we know how the protoype chain works, let's talk about how to best set it up to implement inheritance. I'll use Animal and Dog as example classes.

The naive approach would be to set Dog's prototype equal to Animal's prototype. The problem with this is that they then point to the same object, so any additions you make to Dog.prototype will also be present on Animal's prototype, and thus on all other classes that inherit from Animal.

To avoid this problem, you could set Dog's prorotype to be an object created by calling new Animal(). This object will have a __proto__ property that points to Animal's prototype, so all of Animal's methods will be correctly inherited. Dog will also have its own prototype, so you can create methods for Dog that aren't available to Animal.

However, you end up instantiate a new Animal simply to construct your Dog class. This isn't very semantically sound or eloquent. You also don't actually run the Animal constructor function when you create a new instance of Dog. This means that if Animal's constructor sets a name, you can't just pass in that name when you instantiate a new Dog.

The Solution: Surrogate

A better solution is to combine the previous two techniques by using a surrogate class. The surrogate class' prototype is set to be a new instance of Animal, and Dog's prototype is set to be equal to the surrogate's prototype. You can easily package this into a function to hide these details away. Here's what it looks like:

function inherits(Child, Parent) {
  function Surrogate = function () {};
  Surrogate.prototype = new Parent();
  Child.prototype = Surrogate.prototype;
};

A quick aside: if you simply do the above, then if you call #constructor on an instance of the child class, it will return the parent class. This is because constructor is a property that's automatically set on a class' prototype, but we're overwriting the child class' prototype. The call to prototype will go to Surrogate.prototype, which is an instance of Parent, which will search the parent's prototype and find constructor there.

To fix this, it's advisable to explicitly set the value of constructor for the child class, like so: Child.prototype.constructor = Child;.

What about the code inside the Parent prototype? Inside the child class' constructor functon, you'll need to explicitly call the constructor function, specifying the value of this to be the new instance of the child class. Here's what that looks lik:

function Dog (name, barkVolume) {
  Animal.call(this, name);
  this.barkVolume = barkVolume;
}

This way, all the work that the parent class did to set the name property can be delegated to the parent class, and you can also specify new properties specific to the child class.