Inheritance in JavaScript has been the topic of many discussions in the past and will continue to be the source of future debates and arguments. While we do value composition over inheritance, we don’t want to throw the baby out with the bathwater either. So, from time to time, we run into these cases where we want some notion of inheritance in JavaScript. Now what?
As with many things in JavaScript, there is not a single straight answer. We can choose between a couple of options and many different variations of these solutions. But one thing’s for sure: we can’t have it all!
In this blog post I want to discuss two different styles of inheritance that I have a hard time choosing from when programming JavaScript. And as with everything in life, both styles have their own pros and cons.
Prototypical inheritance
In ‘classical’ programming languages, one class can directly inherit from another class. JavaScript doesn’t have this notion of classes (yet). Instead, JavaScript has prototypes which you can augment to fit your own needs. This means that having a single augmented object as the prototype for other objects, which ‘inherit’ all members of the augmented prototype object, kind of simulates a pseudo-classical inheritance pattern. Let’s talk code in order to demystify this concept.
// validator.js
var Validator = exports.Validator = function() {
this._rules = [];
};
Validator.prototype.addRule = function(rule) {
this._rules.push(rule)
};
Validator.prototype.validate = function(instance) {
...
};
// specificValidator.js
var util = require('util');
var SpecificValidator = function() {
Validator.call(this);
};
util.inherits(SpecificValidator, Validator);
SpecificValidator.prototype.filter = function(instance) {
...
};
// client.js
var validator = new SpecificValidator();
// Calls function on derived object
validator.filter( { ... } );
// Calls function on base object
validator.validate( { ... } );
Here we have a constructor function named Validator which is the base object for other ‘derived’ objects. We augment the prototype with two functions (addRule and validate). Next we define another constructor function named SpecificValidator. We ‘derive’ this new constructor function by calling the base constructor function and wiring the prototype by using the util.inherits() function from the Node.js core library.
We have to use the new keyword in order to instantiate a SpecificValidator object. Now we can use the functions that we added to the prototype.
Functional inheritance
This pattern is advocated by Douglas Crockford in his book JavaScript, The Good Parts. There he offers this particular style as the way to go for inheriting objects. Let’s look at an example.
// validator.js
module.exports = function() {
var rules = [], my = {};
my.addRule = function(rule) {
rules.push(rule);
};
my.validate = function(instance) {
...
};
return my;
};
// specificValidator.js
var validator = require('...').validator;
var specificValidator = function() {
var my = validator();
my.filter = function(instance) {
...
};
return my;
};
// client.js
var validator = specificValidator();
// Calls function on derived object
validator.filter( { ... } );
// Calls function on base object
validator.validate( { ... } );
The base constructor function returns an object that is augmented with functions and is returned at the end. The derived constructor function simple calls the base constructor function and further augments the retrieved object before returning it to the calling code. Here we don’t have to use the new keyword to instantiate anything. Just calling the right constructor function gives us an object which we can use in our client code.
Conclusion
The most important benefit of prototypical inheritance, at least in my humble opinion, is performance. By augmenting the prototype with functions, we only create these functions once. Not matter how many times we instantiate a constructor function, the same functions get (re)used every single time. Functional inheritance on the other hand creates new functions every time a constructor function is called, which is several orders of magnitude slower compared to the prototypical inheritance pattern.
On the other hand, the prototypical approach doesn’t come with encapsulation. Looking at the example shown earlier, the ‘_rules’ property is publicly available to the client code and can be manipulated at will. By using a simple convention, like prefixing with an underscore, we can indicate that these private members should not be touched in order to guarantee a correct behavior. But again, nothing can be enforced. Using functional constructors, we can have private variables and functions that cannot be manipulated by the calling code.
There are more pros and cons, but for me, these are the most important ones to be aware of. You can see that both styles have their strengths and weaknesses. I usually tend to go with prototypical inheritance as this is the ‘JavaScript way’, but I like using the functional approach as well for those cases were I know in advance that not too many objects are created or when I don’t care about performance.
I would love to hear other takes on this. What particular styles do you use? When do you use them and why?
Until next time.