Thursday, April 14, 2016

Why I prefer functional over classical and prototypal inheritance

There are multiple ways in which inheritance can be implemented in JavaScript. In fact so many that the choice easiely gets difficult. I am going to quickly introduce them with a code example and then explain why my recommodation is using functional inheritance in the vast majority of cases.

Classical inheritance

The intention of this pattern (sometimes referred also as pseudo classical inheritance) is to hide away the prototypal nature of JavaScript and look as if JavaScript knew about the concept of classes so that developers coming from languages like Java or C# will find the syntax quite familiar.
Look at this simplified example:

There are quite a bunch of gotchas with this pattern and it's variations (details see for example in the book 'JavaScript Patterns', chapter 'Code reuse patterns'. Another general problem is that classical inheritance hides away the "real", i.e. prototypal nature of JavaScript. Due to these reasons I personally would try to avoid the usage.

Prototypal inheritance

This pattern is based on the Object.create method which was introduced with ES5 and is a more "natural" choice than classical inheritance.

One common gotcha (that also is valid for classical inheritance) comes into play when you have complex objects in the parent:


The reason for the last line's result lies in the way how JavaScript is getting and setting properties.
When getting a property, JavaScript will traverse up the entire prototype chain looking for it and returning the first occurence.
Setting values is different: Javascript will always set a property in the most derived object - but only if it's not a complex object.
What happens here with schwolf.parts.legs = 1 is that - according to the getting rule - the parts object from the base class is returned. Because parts is a complex object it set's it's legs property to 1. And why does this affect all instances? This is the big differnence between prototypal inheritance and Java/C#: prototypes are 'referenced' whereas Java/C# base classes get part of the object and don't share anything with other instances (except for stuff that is explicitely marked as 'static').

Functional inheritance

In his book 'JavaScript: The Good Parts' Douglas Crockford advocates for an approach that he calls 'functional inheritance'. Let's look at an example (btw the usage of ES5 arrow functions and template strings and Object.assign is just for keeping the example concise):


What are the advantages of this approach?
  • easy to grasp - note that we only use functions and no (relatively complicated) prototypes or constructors
  • no gotchas
  • encapsulation (private members), see nameLength variable in person function
  • high performance after object creation

There are unfortunately also some bad news:
  • low performance when creating many objects
  • less dynamic than prototypal inheritance (prototype augmention not possible at any time like with prototypal inheritance)
  • instanceof not possible

But still, in my opinion the advantages of functional inheritance outweight the disadavantages, especially because of the fact that in the vast majority of the real life use cases the mentioned drawbacks are not a really problematic.

Finally a word of caution: do not exaggerate the usage of inheritance, instead adhere to one of the most important OO principles and prefer composition over inheritance!

No comments:

Post a Comment