Reflections on Prototypical Inheritance

JavaScript is an object-oriented language. It uses prototypical inheritance instead of the more common class based inheritance, but luckily it—being the flexible language it is—allows one to utilize both methods of inheritance. But why even allow for both when you usually work with class based models? Well, I can’t speak for the people responsible for making that decision, but I will give you some of my thoughts on the subject.

Now then, what is prototypical inheritance? Douglas Crockford described it so well when he tried to defend it as a full-fledged OO paradigm: “Objects inherit from other objects, what could possibly be more object-oriented than that?”. So that’s it, you don’t create a new object by instantiating a class, you instantiate objects from other objects. By the way, don’t make the mistake of relating prototypical inheritance with the Prototype design pattern, they are very different beasts.

Unfortunately the syntax JS provides for this isn’t very straight-forward. You have to first create a constructor, associate it with the object you want to inherit from (called the prototype) and then instantiate through the constructor. Here’s an example

  1. function Person (name, eyeColor) {
  2. this.name = name;
  3. if (eyeColor) {
  4. this.eyeColor = eyeColor;
  5. }
  6. } Person.prototype = {
  7. age : 0,
  8. eyeColor : "Blue",
  9. father : null,
  10. mother : null
  11. };
  12.  
  13. var adam = new Person("Adam", "Green");

Okay, seeing this doesn’t really distinguish it from class based programming, and this is indeed how you would simulate classes.

I didn’t choose people as an example arbitrarily, I think it can demonstrate an important aspect of prototypical inheritance. Since we want to model reality, let’s look at people this way. The class based solution would probably be to create a Person class and we might provide a constructor for creating a child of two parents. But, do aspiring parents consult some abstract template of a human in order to have children?

For simplicity’s sake, let’s assume that all children inherit traits such as eye color from their father. Here’s a class based solution:

  1. // This would act like a "class method" since it's placed directly on
  2. // the constructor.
  3. Person.create = function (name, mother, father) {
  4. var child = new Person(name);
  5. child.eyeColor = father.eyeColor;
  6. child.mother = mother;
  7. child.father = father;
  8. return child;
  9. }

Here’s the same example using prototypes, letting the child inherit more explicitly from it’s father, it also shows that the setup code get’s fairly awkward with the provided interface (it can be abstracted somewhat).

  1. // Adding an instance method after the prototype has been defined.
  2. Person.prototype.createChild = function () {
  3. function DummyConstructor(father, mother) {
  4. this.father = father;
  5. this.mother = mother;
  6. }
  7. DummyConstructor.prototype = this;
  8. return new DummyConstructor (this, this.spouse);
  9. };

It ended up about the same size as the class based version, but there is one important difference, where did we set the child’s eye color? It’s of course inherited from the father (the prototype). This property is not copied to the child, rather once we try to evaluate child.eyeColor the request will propagate up the “prototype chain” and the father’s eye color will be returned. We can later modify the eye color of the parent and the change will be reflected on the child. We can also set the eye color on the child, which won’t modify the parent, and later on we can delete the property so we once again inherit the eye color. Basically, once we set a value it is set on the outermost object in the chain, but resolving values may cause the aforementioned propagation on the prototype chain. This also means that a minimal amount storage is used when a new object is created, but that might be a later article of mine.

How useful is this? With this example it’s not obviously great and I might update once I think of a relationship that’s more natural to express with prototypes. I imagine there are cases where prototypes would be a perfect fit, and if that’s the case, why would you want to omit them from the language? On the other hand, uses might be such a rare occurance that it can be implemented in the language when the need arises.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options