The Foundations of a JavaScript Programmer: Prototypal Inheritance

JavaScript is a very dynamic language which likes to play fast and loose with traditional programming rules. This makes JavaScript an easy language to learn, but a challenging one to master. The amazing library, jQuery, lowered the bar to being a JavaScript programmer even further by abstracting out the more complex pieces of JavaScript. Modern JavaScript has seen a proliferation of libraries and frameworks making it as easy as it has ever been to program in JavaScript. However, all these tools should not be a replacement for taking the time to learn about the foundations that make JavaScript work. One of those important foundations is how JavaScript manages inheritance. It uses a process called Prototypal Inheritance.

“Each object contains a reference to the object it was derived from”

Prototypal inheritance is different than traditional inheritance. In prototypal inheritance, each object contains a live reference to the object it was derived from. Prototypal inheritance functions like matryoshka dolls (Russian Dolls, pictured above). Russian dolls are a series of almost identical dolls with one exception: each doll is smaller than the next. From largest to smallest, each doll holds the dolls smaller than inside itself. Prototype chains function in a similar way. Every object in JavaScript has a prototype property that is a pointer to the prototype it is based on.

Just like the dolls, once you open the first doll there is another similar but smaller doll inside. For example, we create 2 prototypes in JavaScript. The first is a Person prototype, which we plan to use as a base for more specialized objects. Next, we create an Accountant prototype based on that Person prototype. Each individual object created from the Accountant prototype will have a pointer to the Accountant prototype, which in turn, will have a pointer to the Person prototype. This will be true for all objects in the prototype chain until you reach the end of the chain. Like the smallest doll, the prototype of the final object in the chain has no prototype inside it.

The prototype property is a reference. Our Accountant object’s prototype contains a reference to the Person prototype. This has two very important implications. Firstly, if a change is made to a prototype, all objects with that prototype get the same change. If we have 2 Accountant objects that we made from our Accountant prototype, and we add an “age” property to the prototype then both Accountant objects will have an accessible age property.

“This is because JavaScript will traverse the prototype chain looking for any reference made to an age property”

This where the second implication kicks in. The age property has been added to the Accountant prototype, not the object itself. However, if we check the object for the age property it will return that property. This is because JavaScript will traverse the prototype chain looking for any reference made to the requested property. We can access the age property from our object because the JavaScript engine will check the prototype for the age property once it finds it missing on the object. Likewise, if we had added the age property to the Person prototype, our object would still respond as if it had the age property. The engine will have checked the object, the Accountant prototype, and then the Person prototype. The JavaScript engine will keep opening Russian dolls until it finds the property requested, or reaches the final doll inside that doesn’t open. This is true for functions as well since all functions are handled the same as properties.

There are performance and maintenance pitfalls that all JavaScript developers should be cognizant of from this behavior. For example, it is strongly discouraged to modify the prototypes of native objects like String or Array. Making any change to a native prototype could inadvertently affect code on the page that isn’t yours, or cause a change that isn’t expected, and therefore isn’t caught, until it is too late. On the performance side, an exceptionally long prototype chain can slow down the application as the engine navigates it’s way down the chain looking for a property.

“Understanding prototypes and the way that JavaScript uses them is important for all JavaScript developers to understand.”

The next version of JavaScript, version 6 (more accurately ECMAScript 6), will be adding some syntactic sugar, and some additional functionality, to bring this relationship into a more traditional model. The newer version adds the ability to define classes and subclasses, including keywords like extend and super(). However, under the hood this is still doing the prototype chain operations while adding some protections to avoid the pitfalls mentioned above.

Understanding prototypes and the way that JavaScript uses them is important for all JavaScript developers to understand. Many nuances of the language begin to make a little more sense when you understand the details.