Just as there are many ways to create objects in JavaScript, there are also many ways to replicate class-based, classical inheritance. But the one preferred way to do it is with the Object.create()
method.
var Polygon = function(n) { this.numSides = n; } var Rectangle = function(w, l) { this.width = w; this.length = l; } // the Rectangle's prototype is redefined with Object.create Rectangle.prototype = Object.create(Polygon.prototype); // it's important to now restore the constructor attribute // otherwise it stays linked to the Polygon Rectangle.prototype.constructor = Rectangle; // now we can continue to define the Rectangle class Rectangle.prototype.numSides = 4; Rectangle.prototype.getArea = function() { return this.width * this.length; } var Square = function(w) { this.width = w; this.length = w; } Square.prototype = Object.create(Rectangle.prototype); Square.prototype.constructor = Square; var s = new Square(5); console.log( s.getArea() ); // 25
This syntax may seem unusual to many but, with a little practice, it will become familiar. The prototype
keyword must be used to gain access to the internal property, [[Prototype]]
, which all objects have. The Object.create()
method declares a new object with a specified object for its prototype to inherit from. In this way, classical inheritance can be achieved in JavaScript.
The Object.create()
method was introduced in ECMAScript 5.1 in 2011, and it was billed as the new and preferred way to create objects. This was just one of many attempts to integrate inheritance into JavaScript. Thankfully, this method works pretty well.
We saw this structure of inheritance when building the Maybe
classes in , Category Theory. Here are the Maybe
, None
, and Just
classes, which inherit from each other just like the preceding example.
var Maybe = function(){}; var None = function(){}; None.prototype = Object.create(Maybe.prototype); None.prototype.constructor = None; None.prototype.toString = function(){return 'None';}; var Just = function(x){this.x = x;}; Just.prototype = Object.create(Maybe.prototype); Just.prototype.constructor = Just; Just.prototype.toString = function(){return "Just "+this.x;};
This shows that class inheritance in JavaScript can be an enabler of functional programming.
A common mistake is to pass a constructor into Object.create()
instead of a prototype
object. This problem is compounded by the fact that an error will not be thrown until the subclass tries to use an inherited member function.
Foo.prototype = Object.create(Parent.prototype); // correct Bar.prototype = Object.create(Parent); // incorrect Bar.inheritedMethod(); // Error: function is undefined
The function won't be found if the inheritedMethod()
method has been attached to the Foo.prototype
class. If the inheritedMethod()
method is attached directly to the instance with this.inheritedMethod = function(){...}
in the Bar
constructor, then this use of Parent
as an argument of Object.create()
could be correct.