blog

Image of code from markus-spiske

Prototypal vs. Functional Inheritance in JavaScript

by

If you ever found JavaScript’s prototypal inheritance confusing, do yourself a favor and open this article, open a JavaScript console and code each example in the article. You will definitely come away with a better understanding of how prototypal inheritance works in JavaScript.

After reading the article, I thought a good exercise would be to compare CoffeeScript class definitions vs. the prototypal inheritance style those definitions generate vs. Douglas Crockford’s functional inheritance style outlined in his book JavaScript: The Good Parts.

CoffeeScript Class Definitions

The CoffeeScript homepage gives the following example to demonstrate CoffeeScript’s class syntax:

class Animal
  constructor: (@name) ->
  move: (meters) ->
    alert @name + " moved #{meters}m."
class Snake extends Animal
  move: ->
    alert "Slithering..."
    super 5
sam = new Snake "Sammy the Python"
sam.move()

Anyone experienced with class-based inheritance should have little trouble understanding this code.

Prototypal Inheritance 

The JavaScript generated by the CoffeeScript compiler uses prototypal inheritance. The compiler first generates a utility function that sets the properties on the child constructor and then sets up the prototype chain. It also creates a convenient super property that allows an object to call methods on its prototype.

__hasProp = {}.hasOwnProperty,
__extends = function(child, parent)
{
   for (var key in parent)
   {
      if (__hasProp.call(parent, key))
         child[key] = parent[key];
   }
   function ctor()
   {
      this.constructor = child;
   }
   ctor.prototype = parent.prototype;
   child.prototype = new ctor();
   child.__super__ = parent.prototype;
   return child;
 };

The constructor functions are then generated as follows:

Animal = (function()
{
   function Animal(name)
   {
     this.name = name;
   }
   Animal.prototype.move = function(meters)
   {
      return alert(this.name + (" moved " + meters + "m."));
   };
   return Animal;
})();
Snake = (function(_super)
{
   __extends(Snake, _super);
   function Snake()
   {
      return Snake.__super__.constructor.apply(this, arguments);
   }
   Snake.prototype.move = function()
   {
      alert("Slithering...");
      return Snake.__super__.move.call(this, 5);
   };
   return Snake;
})(Animal);
sam = new Snake("Sammy the Python");
sam.move();

Notice how easily the Snake constructor can access its Animal prototype using the super property.

Functional Inheritance

In JavaScript: The Good Parts, Crockford advocates a functional inheritance style. Converting the original CoffeeScript code to this style results in the following:

Function.prototype.method = function(name, func)
{
   if (!this.prototype[name])
   {
      this.prototype[name] = func;
      return this;
   }
};
Object.method('superior', function(name)
{
   var that = this;
   var method = that[name];
   return function()
   {
      return method.apply(that, arguments);
   };
});
var Animal = function(spec)
{
   var that = {};
   that.name = spec.name;
   that.move = function(meters)
   {
      alert(this.name + ' moved ' + meters + 'm.');
   }
   return that;
}
var Snake = function(spec)
{
   var that = Animal(spec);
   var super_move = that.superior('move');
   that.move = function()
   {
      alert('Slithering...');
      super_move(5);
   }
   return that;
}
sam = new Snake({name:'Sammy the Python'});
sam.move()

The functional style does nothing with prototypes. Inheritance is implemented by creating an object from a base function, similar to a constructor, but without the need for the new operator. Access to super methods is accomplished by extending the built-in Object and Function objects. Notice that any child object wanting access to a super method must create a new function pointing to the super method.

Which One?

So which method is better? Because I’m more familiar with class-based inheritance, I’d rather just use CoffeeScript and ignore the underlying JavaScript implementation altogether. I like the fact that I can look at a CoffeeScript class definition and see on a single line both the name of the "class" and the name of the "class" it extends. In both JavaScript implementations, I have to search other lines to find the object that my object is extending. I find the use of the super property a much more elegant solution when it comes to super methods. The functional method for accessing super methods would not scale well if there are a large number of super methods you want to access.

Even if you decide to work at the CoffeeScript level, it’s imperative that you understand the JavaScript it compiles into. Again, read the article referenced above and the generated JavaScript becomes trivial to understand.

Finally, if you want a much more thorough comparison and richer examples of prototypal vs. functional inheritance styles, this article provides both and makes a very strong case for the use of prototypal inheritance.

+ more