Using Super Constructors Is Critical In Prototypal Inheritance In Javascript

Posted April 17, 2009 at 10:07 AM by Ben Nadel

Tags: Javascript / DHTML

I like to think that I have a pretty decent understanding of the inheritence mechanisms available in Javascript. But last night, I started reading Pro Javascript Design Patterns by Ross Harmes and Dustin Diaz and I discovered that there were some glaring omissions in my understanding of how prototypal inheritence works. First off, I just want to give the book a huge shout out because Pro Javascript Design Patterns explains prototypal inheritence better than anything else that I have read in other books or on the web; their explanations are very thorough and well articulated. And I'm only through chapter 4 - I'm sure the next 13 chapters are gonna be page turners!

 
 
 
 
 
 
Pro Javascript Design Patterns By Ross Harmes And Dustin Diaz. 
 
 
 

To understand my misunderstanding, it is first important to get a quick understanding of what prototypal inheritence is. In Javascript, everything is an object. And, each object is part of a prototype chain. Each object in a prototype chain defines a "prototype" of the object below it. By "prototype", what I mean is that it defines a default of what the next object should look like. To help visualize this, I have created the following graphic:

 
 
 
 
 
 
Prototype Chain Inheritence In Javascript. 
 
 
 

As you can hopefully see from the graphic, the final class, as seen by the outside world, appears to have all of the properties defined within the entire protoype chain. When I say "appears", I mean that while it seems as though the final class has all of these properties, it does not actually contain them. Behind the scenes, what happens is that when you access a property on the final class, Javascript will keep moving up the prototype chain in search of the requested property until it finds it (in which case it returns the value) or until it hits a null prototype, in which case it returns undefined (or throws an error).

At first glance, this might seem like inheritence as you know it in other languages; but, there is one huge caveat! In typical inheritence, each sub-class gets a copy of its base class. In prototypal inheritence, on the other hand, for each set of sub-classes, there is but one single prototype instance and each sub-class merely gets a pointer to that prototype (base class).

 
 
 
 
 
 
Prototype Instance Is Shared By All Sub-Class Instances In Javascript's Prototype Inheritence Architecture. 
 
 
 

Normally, this doesn't matter to us because 95% of inheritence is method-based; meaning, we use inheritence to factor out common methods into base classes so that they don't have to be redefined in all of our sub-classes. It's the other 5%, the property-based inheritence, that can really trip us up if we don't fully understand prototypal inheritence. And of this 5%, really, the only tricky part involves complex property values.

Simple pass-by-value properties, such as strings and numbers never cause a problem because of the asymmetrical reading and writing of properties in the prototype chain. This is the part I didn't understand at all until I started reading Pro Javascript Design Patterns. See, when you read a property from an object, it travels up the prototype chain looking for it (see diagram above). But, when you write a property to an object, Javascript always writes it directly to the sub-class (not back into the object prototype). In doing this, Javascript allows each sub-class to leverage the default values defined in its prototype chain while maintaining a separate, unique set of instance values when it updates properties.

While this is an amazing architecture for memory conservation, we run into problems when we read and update complex pass-by-reference properties defined in our prototype chain. When you read a complex object property, Javascript climbs the prototype chain looking for it as normal. But, because the object is pass-by-reference, it doesn't return a copy of it; rather, it returns a reference to the original object contained in the Prototype. When you then update a key within that object reference, you are altering the Prototype itself. And, since each instance in a set of sub-classes points to the same Prototype instance (see diagram above), updating a complex property updates all sub-class instances (not just the one in question).

To demonstrate this, I will define a base class with both a complex and simple property, then define two sub-class instances and update each property respectively:

  • <script type="text/javascript">
  •  
  • // Create a base class to sub-class.
  •  
  • function Base(){
  • this.SimpleProperty = "Simple";
  • this.ComplexProperty = {};
  • }
  •  
  • /* ------------------------------------- */
  •  
  • // Create sub-class and extend base class.
  • SubClass.prototype = new Base();
  • SubClass.constructor = SubClass;
  •  
  • function SubClass( strProperty ){
  • this.SubClassProperty = strProperty;
  • }
  •  
  • /* ------------------------------------- */
  •  
  • // Create two instances of sub-class.
  • objA = new SubClass( "ObjA" );
  • objB = new SubClass( "ObjB" );
  •  
  • // Update the simple property in the base class.
  • objA.SimpleProperty = "SimpleA";
  • objB.SimpleProperty = "SimpleB";
  •  
  • // Update key in complex property in the base class.
  • objA.ComplexProperty.AKey = "FromA";
  • objB.ComplexProperty.BKey = "FromB";
  •  
  • // Log updated property profiles.
  • console.log( objA );
  • console.log( objB );
  •  
  • </script>

When we run this code, we get the following console.log() output:

 
 
 
 
 
 
Updating Complex Properties In The Prototype Chain Without Calling The Base Class Constructor. 
 
 
 

As you can see in the console output, updating the "ComplexProperty" updated both instances of the sub-class. Now, we are really seeing how prototypal inheritence is different from typical inheritence!

All of the above gets us to the main point of this blog post - super constructors are a crucial ingredient to effective prototypal inheritence. When you are using prototypal inheritence, you should always call the super constructor from the sub-class constructor to make sure that your sub-class instance gets a unique copy of all properties, simple and complex. We can still use the prototype chain to define global copies of the methods (awesome memory conservation); but, by calling the super constructor with the sub-class context, we force the prototype to copy all default values into the instance of our sub-class.

To illustrate this point, I will take the above demo and add the super constructor call from within the sub-class constructor:

  • <script type="text/javascript">
  •  
  • // Create a base class to sub-class.
  •  
  • function Base(){
  • this.SimpleProperty = "Simple";
  • this.ComplexProperty = {};
  • }
  •  
  • /* ------------------------------------- */
  •  
  • // Create sub-class and extend base class.
  • SubClass.prototype = new Base();
  • SubClass.constructor = SubClass;
  •  
  • function SubClass( strProperty ){
  • // Call super constructor.
  • Base.call( this );
  • this.SubClassProperty = strProperty;
  • }
  •  
  • /* ------------------------------------- */
  •  
  • // Create two instances of sub-class.
  • objA = new SubClass( "ObjA" );
  • objB = new SubClass( "ObjB" );
  •  
  • // Update the simple property in the base class.
  • objA.SimpleProperty = "SimpleA";
  • objB.SimpleProperty = "SimpleB";
  •  
  • // Update key in complex property in the base class.
  • objA.ComplexProperty.AKey = "FromA";
  • objB.ComplexProperty.BKey = "FromB";
  •  
  • // Log updated property profiles.
  • console.log( objA );
  • console.log( objB );
  •  
  • </script>

The only update I made is that I call the Base method (base constructor) within the sub-class constructor:

  • Base.call( this );

Now, when we output the FireBug console, we get the following:

 
 
 
 
 
 
Updating Complex Properties In The Prototype Chain After Calling The Base Class Constructor. 
 
 
 

As you can see, each object now has a unique copy of all the properties and as such, updating the ComplexProperty, which is still pass-by-reference, is not affected by other instance activities.

Javascript's prototypal inheritence is an awesome inheritence architecture and provides the most excellent memory management. But, if you don't fully understand how it works, it can certainly come back to bite you in the butt. So, my closing words of advice: always call the super constructor from within your sub-class constructors! And, while I have not finished Pro Javascript Design Patterns, I'm already recommending that you check it out.




Reader Comments

Apr 17, 2009 at 10:24 AM // reply »
4 Comments

You should read JavaScript: The Good Parts (Paperback)
by Douglas Crockford(http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1). For me it was an real eye opener. I haven't read the book you are reading now, but Crockford's book is real thin, hardly 200 pages, but is crammed with useful stuff that has changed the way I write javascript. Highly recommended. And another book worth mentioning
is John Resigs book about Javascript. John Resig knows some javascript (big understatement).


Apr 17, 2009 at 10:39 AM // reply »
67 Comments

This is essentially the same problem faced by ColdFusion when you start passing around CFCs and other complex objects/datatypes. It's also one of the problems that brought to the fore the need for cflock. Explicit calls to Duplicate() perform the same trick as calling a prototype's constructor.

Or, in musical terms, always remember:

"And you may find yourself in a beautiful house, with a beautiful Wife. And you may ask yourself-well...how did I get here?"

Now that work is being done to move JavaScript to multi-threaded within the same page, we're going to start seeing the same growing pains that ColdFusion had -- most programmers have a hard time wrapping their head around reentrant programming.


Apr 17, 2009 at 10:43 AM // reply »
11 Comments

Great post Ben!

Just ordered "Pro Javascript Design Patterns" off Amazon.


Apr 17, 2009 at 10:46 AM // reply »
11,232 Comments

@Marko,

Yeah, I hear that book is really good. I have it on my list of things to read!

@Rick,

At least in ColdFusion, when you use the Extends keyword in components, your sub-classing gets a fully copy of the base class. So, you don't have to call the super constructor if you don't need to. Although, if the super-class constructor defines properties, than you have to anyway to get them defined :)


Apr 17, 2009 at 10:47 AM // reply »
11,232 Comments

@James,

Awesome my man. I hope you like it. I'm really liking it so far.


Apr 17, 2009 at 11:03 AM // reply »
16 Comments

A good explanation of prototypal inheritance Ben. Javascript the definitive guide (5th edition) also does justice to this subject


Apr 17, 2009 at 11:46 AM // reply »
11,232 Comments

@William,

Perhaps I'll put that on my list too. So many good books to read.


Apr 17, 2009 at 11:58 AM // reply »
132 Comments

@RickO

Who is multithreading JavaScript?

To my knowledge all browsers single thread JS execution. I've not seen anything about adding support for threading constructs.


Apr 17, 2009 at 7:34 PM // reply »
29 Comments

Love that crazy typeface in yer diagrams, Ben! Wherever did you come by it? :)


Apr 19, 2009 at 12:40 AM // reply »
11,232 Comments

@David,

I got it with a package of handwritten fonts that someone posted once. I enjoy it :)


Apr 20, 2009 at 1:10 PM // reply »
1 Comments

Hi Ben, I highly recommend Douglas Crockford's book (it's expensive so get it second hand from Amazon).

The Pro JavaScript Design Patterns book is awesome too, possibly my favourite on the subject of Object-Oriented JavaScript.

Easily the best two books on JavaScript.

If everyone read both these books back in the mid-90's (well my starting point is 1999), wow what a better place the world would be :)


Apr 21, 2009 at 8:24 AM // reply »
11,232 Comments

@Mark,

Yeah, I've heard Crockford's book is really good and surprisingly funny. It's definitely on my list!


Jul 22, 2011 at 2:44 PM // reply »
2 Comments

@Ben, one question - if you make copies of all the properties and methods by calling Base.call(this); what's the point of having: SubClass.prototype = new Base();?

And is this an actually suggested pattern by: Pro Javascript Design Patterns by Ross Harmes and Dustin Diaz?


Oct 1, 2011 at 1:03 PM // reply »
2 Comments

I love that graphic at the top, it's a perfect diagram of inheritance. :)


Nov 9, 2011 at 5:16 PM // reply »
1 Comments

That it is "critical to call your super class constructor in inheritance" has been known for at least 10 years - I first read it here: http://www.webreference.com/js/column79/index.html. Not to detract from your point, but it is frustrating to see each new crop of javascripters running into the same issues over and over again. It's more a comment on the state of javascript than anything else :)


Dec 18, 2011 at 8:46 PM // reply »
2 Comments

Usage of the following script helps enforce the policy of always calling the parent constructor in the case where default (object) values have been set to properties on the parent "class." Not fool-proof, but should work well to prevent most problems...

  • Function.prototype.extend = function(construct) {
  • construct.prototype = new this();
  • construct.prototype.parent = construct.prototype.constructor;
  • construct.prototype.constructor = construct;
  •  
  • //set all object properties to null to avoid multiple instances referencing the same object,
  • //in the case that the parent class had set default values in the constructor
  • //(note that this is only an issue when the default value was set to an object - literal values are fine)
  •  
  • for (var i in construct.prototype) {
  • if (typeof construct.prototype[i] == 'object') {
  • construct.prototype[i] = null;
  • }
  • }
  •  
  • return construct;
  • };
  •  
  • // Usage:
  •  
  • var sup = function(a){
  • this.a = a;
  • }
  • sup.prototype.m = function(){
  • console.log('sup calling m()');
  • };
  • var sub = sup.extend(function(b){
  • this.parent('a');
  • this.b = b;
  • });

This code is my takeaway from a conversation I just had with the author of this post:
http://upshots.org/javascript/really-simple-javascript-inheritance



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools