Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Henry Hollenstain
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Henry Hollenstain ( @hhollenstain )

Using Super Constructors Is Critical In Prototypal Inheritance In Javascript

By on

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!

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.

Want to use code from this post? Check out the license.

Reader Comments

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).

68 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.

15,640 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 :)

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.

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 :)

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?

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 :)

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

1 Comments

Hi Ben,

First off, great article (as always!). But I wanted to note especially on the aspect of "calling super".

This is a technique I've employed for a while, though it has its pitfalls...

"
// 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;
}
"

This is a great approach unless you're NOT employing "this" for your classing.

To demonstrate, change:

// Create a base class to sub-class.

function Base(){
this.SimpleProperty = "Simple";
this.ComplexProperty = {};
}

To:

// Create a base class to sub-class.

function Base(){}
Base.prototype = {
SimpleProperty : 'Simple',
ComplexProperty: {}
};

We then see that we have not inherited any properties :(

I would say I'm "the biggest JS advocate", though, I feel the Prototypal Inheritance model is failing -- in its current implementation in JS -- in part, due to the matter that designing 'sub-abstractions' (subclass inheritance) is dependent upon Implementation ( Sub.prototype = new Base() ).

/**
* How can we have a universal approach to this?
*/

Either way, thanks a ton for the great article and ditto on the Pro JavaScript Design Patterns reference -- its a must for JS devs.

Cheers,

Cody

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel