Javascript Prototype and Multiple Inheritance with dojo.declare - Redfin Real Estate News

Javascript Prototype and Multiple Inheritance with dojo.declare

by
Updated on October 5th, 2020
Coming from the C++ background into javascript programming was a fun ride. I read many blog posts and articles about javascript inheritance, and after reading it all I still felt I didn’t fully understand how javascript inheritance really works. I soon realized the hard truth: I’ll have to figure it out on my own. I installed the javascript console and played with it till the cows came home. Without further ado open your javasript console. I suggest node.js, trust me it will make your day, or at least, it won’t ruin it 🙂 Chrome inspector console is pretty nice too, just press Shift+Enter to move to the new line. We will first see how inheritance can be implemented using pure javascript and then we will see how it’s handled for you or hidden from you, by some popular frameworks out there. If you are a prototype wizard, skip to Multiple Inheritance with dojo.declare.

Javascript Prototype

Lets create an empty object:

> var A = new Object()
{ }
> A.prototype
undefined

What, A doesn’t have a prototype?! A is an object. Only functions have prototypes.

> var F = function() {}
> F
[Function]
> F.prototype
{ }

But wait, aren’t functions just objects in javascript? Well yes, but somewhat special objects. If you have a problem with that just refer to George Orwell’s definition from the Animal Farm: “All animals are equal but some animals are more equal than others.” Functions are special objects that can be used to instantiate other objects. Just add new before the function call and any function becomes a valid javascript class constructor.

> var Cake = function(name) {
..... this.name = name;
..... }
> var yellowCake = new Cake("yellow");
{ name: 'yellow' }

When you call a function using new, javascript creates a new empty object { } and passes it as this context to the function. We could have achieved the same without ever using the keyword new. Lets try that just out of spite.

> var cakeFromScratch = { }
> Cake.call(cakeFromScratch, "Look ma no new");
> cakeFromScratch
{ name: 'Look ma no new' }

We passed in empty object cakeFromScratch as this context using javascript call method, and Cake function has initialized its member name as expected. Now, we all know that good cakes should have a chocolate crust on top so lets add it to the prototype of the Cake function, then all cakes we already created will instantly get it.

> Cake.prototype = { crust : “chocolate” }
{ crust : “chocolate” }
> yellowCake.crust
undefined

Blasphemy!!! yellowCake has no crust! Isn’t it supposed to get it automagically? When we created yellowCake object, Cake.prototype was pointing to an empty object A. By executing Cake.prototype = {crust : “chocolate”} we have set the prototype to point to a new object B, while yellowCake instance is still pointing to A. In other words, we have changed to what Cake.prototype points to instead of updating it. This is what happened in memory across time:

Every object in javascript has a “secret” __proto__ field. When object is created using new, __proto__ is set to point to parents function prototype. What we should have done to make all cakes have crust  is this:

> Cake.prototype.crust = “chocolate”;

Now we have changed the original prototype object. Don’t let javascript confuse you with it’s fancy names, prototype is just a member variable of a function object and is initially set to an empty object { }. You can change it entirely, add to it and remove from it.

> yellowCake.crust
'chocolate'
> cakeFromScratch.crust
undefined

Oh-oh, now cakeFromScratch has no crust! Well, since we manually initialized cakeFromScratch object, __proto__ was not set for us automatically. But we can fix that.

> cakeFromScratch.__proto__ = Cake.prototype
> cakeFromScratch.crust
'chocolate'
> cakeFromScratch instanceof Cake
true

Ta-da! We have manually created a legitimate cakeFromScratch without ever using new and as you can see, the instanceof operator agrees. The existence of __proto__ means that in javascript, we can easily change the type of object dynamically. Probably not the smartest thing to do but hey if God didn’t want us to mix cakes and donuts why did he give us both?

> var Doughnut = function() {}
> Doughnut.prototype.glaze = "vanilla"
> yellowCake.__proto__ = Doughnut.prototype
> yellowCake.glaze
'vanilla'
> yellowCake instanceof Doughnut
true

yellowCake is now a Doughnut. Strange but we can do it! The point of this exercise was not to demonstrate a clever pattern that should be used in real life, trust me, this one might be just a little too clever, but to demonstrate that the type of object is determined only by its __proto__ . It’s time to move on to inheritance. Not a problem, just make function.prototype point to an object you want to inherit from.

> var Dessert = function(calories) {
..... this.calories = calories;
..... }
> Dessert.prototype.yummy = "yes"
> Cake.prototype = new Dessert(100);
 { calories: 100 } 

Cake now inherits from Dessert and it has same members that Dessert has. Members added to function prototype are shared fields. Fields added to this are member variables. Basically all desserts are yummy but they have different calories. That is, they should have different calories.

> var tiramisu = new Cake("tiramisu")
{yummy: 'yes', calories: 100}
> var cheeseCake = new Cake('cheese cake')
{yummy: 'yes', calories: 100}

Houston, we have a problem. Certainly both tiramisu and cheeseCake are yummy, but they should have different calories! When we created our objects,  __proto__ field was set to whatever Cake.prototype was pointing to, which was an instance of Dessert object. A specific instance of Dessert object. In fact, an instance that has its calories count set to 100.

> tiramisu.__proto__
{ calories: 100 }

How do we initialize parent member variable calories in our constructor? We call the parent functions to do its part:

> var Cake = function(name, calories) {
..... Dessert.call(this, calories);
..... this.name = name;
..... }
> var tiramisu = new Cake("tiramisu", 300)
 { calories: 300, name: 'tiramisu' }

Excellent, tiramisu now has 300 calories. I know, I know… 100 was better. Don’t despair, the “calories = 100” member still exists!

> tiramisu.calories
300
> tiramisu.__proto__.calories
100

What we did in our constructor is create a field with the same name calories in the top level object, effectively masking the inherited calories in the __proto__ object. This is what prototype chaining is all about. When you “get” a field Javascript engine will dig down the __proto__ chain until it finds it or runs out of __proto__ objects. On the other hand setting a field is one lazy operation, it only operates on the top level object. If the field is there it will get updated, if not, it will be created. In the end, it all works out as expected.

Can we do better? Can we avoid having two calories fields?
The trick is to use Object.create instead of new. https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create

> var baseObject = Object.create(Dessert.prototype)
> baseObject.yummy
'yes'
> baseObject.calories
undefined

Object.create() returned a new empty object with only its __proto__ set to Dessert.prototype. It never called the constructor. To summarize:

new Dessert(x)
1. creates new empty object A = {}
2. sets A.__proto__ to Dessert.prototype
3. calls Dessert function with object A as this context to initialize the member variables
4. returns A to the caller

Object.create(Dessert.prototype)
1. creates new empty object A = {}
2. sets A.__proto__ to Dessert.prototype
3. returns A to the caller

We can now use the baseObject for our inheritance chain to avoid having two calories fields

> Cake.prototype = baseObject
> var tiramisu = new Cake("tiramisu", 300)
> tiramisu
{ calories: 300, name: 'tiramisu' }
> tiramisu.__proto__.calories
undefined

Dojo has a nice browser-compatible trick for doing this:

// return a new object that inherits from ctor.prototype without running ctor on the object.
function forceNew(ctor) {
    // create object with correct prototype using a do-nothing constructor
    xtor.prototype = ctor.prototype; // xtor is a global empty function
    var t = new xtor;
    xtor.prototype = null; // clean up
    return t;
}

Just in case you’re wondering why do we even need a new object for our prototype hierarchy and why don’t we just do

> Cake.prototype = Dessert.prototype

Well because this wouldn’t be inheritance. Anything we add to Cake function prototype would now be visible in its parent Dessert class as well. We need a new object instance for our prototype so that we can add custom, Cake specific fields, without touching our parents prototype.

Multiple Inheritance with dojo.declare

First of, multiple inheritance is not really supported by the language, but there are ways around it, so to speak. In dojo, one can do the following to declare a Cake class, along with its parent classes

dojo.declare("Dessert", null, {
    yummy: "yes"
});
dojo.declare("BirthdayItem", null, {
    event: "birthday"
});
dojo.declare("Cake", [ Dessert, BirthdayItem ], {  
    name: null
});

How does this work? The truth is that only the first listed class is a true prototypical parent, while all the others are just “mixed in”. Dojo will create a new proto object for every mixed-in parent and then copy all the properties from the parent to the proto object. It will then chain these objects to create a custom prototype chain for your declared class.
Here is the relevant code from dojo, a little simplified to be more readable.

if (superclass) {
    for (i = mixins - 1; ; --i) {
        proto = forceNew(superclass); // forceNew from the previous section
        if (!i) {
            // stop if nothing to add (the last base)
            break;
        }
        // copy everything from base class prototype to proto object
        nextBase = bases[i]; // bases? - see below
        mixin(proto, nextBase.prototype); 

        // create new empty constructor function to chain in our proto object 
        ctor = newFunction;
        ctor.prototype = proto;
        superclass = ctor;
    }
}

This code is a little complicated, so you should stare at it for a while. Ready? Only the first time through the loop we use the real superclass (Dessert in our case) to create the proto object. Every other time when we call forceNew() the superclass is a custom function object we created on the last three lines. Basically, we create the new proto object, fill it up, then make an empty function ctor that inherits from it, and finally use ctor to create the next proto object. In the end we have created the proto chain. This is what the final result looks like:

> Cake.prototype { 
    declaredClass: "Cake",
    name: null,
    __proto__: {
        declaredClass: "BirthdayItem",
        event: "birthday",
        __proto__: {
            declaredClass: "Dessert",
            yummy: "yes",
            __proto__: Object // root javascript Object
        }
    }
}

How does dojo decide what is the correct stacking order of the base classes and where does bases array come from? What if Dessert inherits from A then B, while BirthdayItem inherits from B then A? Which should come first in the Cake prototype chain: A or B? Well, it’s complicated, and you can read about it here http://www.python.org/getit/releases/2.3/mro/

Things to note:

1. Only the first base class in the list is a true prototypical parent.
If we change Dessert.prototype, Cake objects will reflect the change. However, cakes will be oblivious to changes that we make to BirthdayItem.prototype.

> Cake.prototype.__proto__ === BirthdayItem.prototype
false
> Cake.prototype.__proto__.__proto__ === Dessert.prototype
true

2. Fields are overridden from left to right.
If we had a field with the same name in multiple base classes, the field from the last listed class would win. This fact gave us a headache a few times. For example if Dessert had “color”: “blue” and BirthdayItem had “color”: “red”, our Cakes would be red.

3. Don’t use multiple inheritance
Java doesn’t even have it, C++ does but we all know how widely this feature is used in practice. Javascript doesn’t support it either and even though we can beat it into submission doesn’t mean we should. Instead, try to go back and think more about your class design.

4. Use mixins instead
Mixing in is copying fields from source object to destination object. Rather than using multiple inheritance and thinking about multiple parent objects, think about functions and design a batch of functionality. You can than mix it in wherever it’s needed: with prototype or with a specific object instance. Learn more about it here: mixins at twitter.
Rather than creating prototype chain, just extend your object with a mixin:

extend(Cake.prototype, BirthdayMixin); // mixin as an object - works by copying all members
or
BirthdayMixin.call(Cake.prototype); // mixin as a function - works by assigning to this

5. Think about performance
To chain in multiple base classes we have to create custom constructors and copy all the fields from base class to the new object. We can’t just point to base.prototype. We also have to decide the correct stacking order, and as I already mentioned, that step is a little complicated. Just look at that Method Resolution Order document, I’m not sure I want to understand everything that’s happening there. It might give me nightmares. On top of that, we can’t delay this work, it is done before we create instances of our class. This hurts first-load performance. Using mixins alleviates the problem and you can perform “mixing in” anytime you like. Maybe when the object is instantiated, maybe later. You gain grater flexibility and less headaches.

Be the first to see the latest real estate news:

  • This field is for validation purposes and should be left unchanged.

By submitting your email you agree to Redfin’s Terms of Use and Privacy Policy

Scroll to Top