Pages

Friday, May 24, 2013

JavaScript Inheritance - HowTo Shoot Yourself In the Foot With Prototypes!


One thing that has long eluded me is a good understanding how JavaScript inheritance works when the parent constructor function has instance properties. The following code has a Widget parent class that has a messages properties. In this case we want each instance to be initialized with an empty messages array:



Before we set SubWidget's prototype to a new instance of our Prototype constructor on line 12 we get an object graph that looks like this:

After the code on line 12 is run the new keyword does its magic and ties everything together creating a new inheritance tree and a new scope.  Our object graph now looks something like this:

Do you see what the problem is yet? Lets create some instances of our subclass to highlight the issue:


Now our object graph looks like this:



Before I talk about the real problem here I'd like to step back and talk about the "type" property on the widget's constructor.  If it is not initialized by assignment each instance's "type" property actually points to the constructor's "type" property.  However, once it is initialized by assigning a value to like so: sub1.type = 'Fuzzy Bunny' it becomes a property of the instance, as shown in the new object graph:

Our bug should start to become clear now.  Let's look at the value of both sub1 and sub2's messages array:

JS Bin

Each object is sharing the same messages array! It would be tempting to fix this by adding another property to the SubWidget constructor like so:



However, what if we wanted to create other objects that extended Widget?  That new object would also need a messages array and pretty soon we have code that is a nightmare to maintain and extend.  Additionally, what if we wanted to add other properties to the Widget constcutor that were initialized when instances of its sub classes were constructed?  This isn't very reusable or flexible solution. 

In order to properly fix this all that needs to be done is  to add a single line of code to our SubWidget constructor that will invoke the Widget constructor with the same scope of our SubWidget constructor:



Now when we create new objects each instance has a new instance of the messages array:

JS Bin

Now our object graph is correct: