Javascript Inheritance & The Evil Dead

Javascript is a wily beast. Its popularity has skyrocketed in the last few years. With great options like Angular and React for front end development and Node.js for the back end, it seems like javascript is everywhere. And it kind of is. According to a StackOverflow poll, javascript is not only the most popular front end language by far, but also the most popular back end language as well.

Still ES5, the most prolific version of the language, can be quite tricky. In fact, it reminds me of those persistent deadites from Evil Dead series. Just when you think you've got it beat, some unholy aspect of the language rears its putrid, moldering head causing bugs and making your life unpleasant. Things like variable hoisting, the handling of the this keyword, and closures all are constant headaches for developers everywhere. But one aspect of the language that I used to find particularly treacherous is the way that inheritance works. What is prototypical inheritance? What that's __proto__ thing I keep seeing? Where does the Object base class fit in?

In this case, dismemberment by chainsaw isn't going to help. To cast the evil back into the abyss, you have to get under the hood and understand how javascript's inheritance mechanisms work. But enough beating the undead horse. Reload your Boomstick™ and strap a chainsaw to your stump. It's gonna get messy.

It's objects all the way down

Just about everything you work with in javascript is actually an object. Of course object literals you create like this are objects:

But did you know that functions are objects too? Try this:

Uh-huh, that's right. You just added a property to a function. As it turns out, functions are objects just like objects are objects so adding properties to them is totally legal. Actually this is a key detail of implementing inheritance in javascript, as you will see shortly.

FYI, arrays are also objects. Pretty much everything except primitive types (strings, numbers, booleans) are objects.

That prototype thing

As mentioned above, functions are objects. But what's more, they have a special property on them called prototype. This property points to a simple object where you can store pretty much whatever you want. You see this a lot when people declare "classes" in javascript.

Here we are adding a property called numBarrels and a function called fire to the prototype property hanging off the Shotgun function (I mean object). Notice that after creating the function and immediately logging the prototype object to the console, we do not get undefined. It's an empty object, but it's an object nonetheless! Of course after adding some properties to it, we see the those echoed back on the next call to console.log().

The important thing to remember here is that all functions are objects and they come with a built in property called prototype that points to an empty object.

That other __proto__ thing

All objects in javascript have a special internal property called __proto__. Try this

You can see it's basically just an empty object (it's actually not empty but everything on it an internal property).

What is this property all about? Well it plays a major role in how javascript resolves property names. When you do something like this:

Javascript will first look at the o object for a property on it called catchphrase. If it cannot find one it will check whatever object that __proto__ points to for that property. If it's not on that object, it will look at the object pointed to by that object's __proto__ property. It will continue doing this until it finds the property or it runs out of objects to check (i.e. it finds a __proto__ with a value of null). This traversal mechanism is one of the basic concepts of javascript's prototypical inheritance concept. Try this:

These all run fine and are perfectly valid properties to access through that object. But if we didn't define them, how did they get there? Well it turns out they are defined on the built in Object.prototype object. Try this:

You will see toString, constructor, and several more.

"Okay", you say, "but what does that have to do with the object literal o above?"

Great question. You may be aware that the Object function is kind of the base class of all objects in javascript. But what you may not have known is that the __proto__ property is the linkage that makes that happen. You see, when you create an object literal in javascript, the engine will set that's object's __proto__ property to Object.prototype. Yes, the Object function has the very same prototype property on all functions that I mentioned above.

So when the javascript engine sees o.constructor it looks on the o object for a property called constructor and doesn't see one. So it follows the __proto__ pointer up to Object.prototype and looks there. Lo and behold, there it is.

Adding properties to Object.prototype is one way you can add new functionality to all your objects. If you add a new property called necronomicon to Object.prototype, that property will now show up on all objects.

As it turns out, you can even make an object's __proto__ point to any old random object (or null). Just for fun try this:

Here we create a new object literal and immediately try to access a property called deadByDawn. Of course, that property doesn't exist on that object so the engine looks at __proto__ which points to Object.prototype and checks there. It doesn't exist there either so undefined is output. But then, we change __proto__ to point to an object that does have a property on it called deadByDawn. Now when the javascript engine can't find it on o, it follows __proto__ to alt and voila, it finds deadByDawn!

Now before we move on, I'll get nerd slapped hard if I don't warn you that changing the __proto__ property on an object is dangerous so I don't recommend actually doing that outside of educational purposes.

Also it's worth mentioning that the __proto__ property isn't technically what javascript uses to traverse the prototype chain. It actually uses an internal property called [[Prototype]]. The __proto__ property is actually a getter/setter for [[Prototype]] so while they're not really exactly interchangeable, I'm going to use __proto__ in this article because it's easier to work with.

Ways to create things

Let's look at a few ways to create objects in javascript and see how the __proto__ pointer is affected. We already know that when you create an object literal in javascript that its __proto__ pointer gets set to Object.prototype:

That's great, but what about when people create objects from classes they wrote?

So here we create a basic javascript class then create an object from it. Notice that when we output scatterGun it's an empty object. But when we call the fire() method it works. Why is that? Where did the fire property come from? Well the answer here is that when you new an object using a class (that is, a constructor function like Shotgun), the engine will set the __proto__ property of that object to the prototype property of the constructor function you used (in this case Shotgun.prototype).

You can verify this by running the following code:

So when you try to access scatterGun.fire and the javascript engine doesn't see it on the scatterGun object, it follows __proto__ up to Shotgun.prototype where it does find it.

There's one more way to create objects that I want to cover, the user of Object.create():

What's going on there? Well as it turns out that is quite relevant to our discussion because what this method does is to create an object and set its __proto__ pointer to whatever object you pass in:

It has the same effect of setting o.__proto__ to alt. Neato, so what's this have to do with inheritance?

Inheritance

For your consideration, a class called Shotgun:

Now here is a class that derives from Shotgun:

If you've read this far, then probably wondering about this line:

Well, that's the line where all the rich, creamy inheritance happens. Remember that that Object.create() creates an object and sets its __proto__ property to whatever object you pass in. Well here we are passing in the Shotgun.prototype object. That links the __proto__ pointer inside the Boomstick.prototype object to the Shotgun.prototype object. And since we did not modify Shotgun.prototype, it still points to Object.prototype.

"Wait, what? The prototype object has a __proto__ property on it?"

That was you asking that. And yes it does. Remember that I said all javascript objects have a __proto__ property? Well I meant it. Since prototype is just a regular object it has one too. And since the Boomstick function is also an object, it has one as well. So both Boomtick.__proto__ and Boomstick.prototype.__proto__ exist. In this case, we only care about the latter.

So here we have a class Shotgun that defines two methods, fire and reload, and a class Boomstick that inherits reload and overrides fire.

So when we call splatterGun.fire() the javascript engine first looks at the splatterGun object and doesn't see a fire property. So it follows splatterGun.__proto__ up to Boomstick.prototype and finds fire, so it calls it. That's why splatterGun.fire() outputs "BOOM!" rather than "bang".

Now when you call splatterGun.reload(), the engine won't find reload on splatterGun or on Boomstick.prototype. So it follows Boomstick.prototype.__proto__ up to Shotghun.prototype where it does find reload and executes it.

What if we access splatterGun.toString()? In that case the javascript engine will follow the prototype chain all the way up to Object.prototype to find the toString() method. Of course, if you override it at any other level (say in Boomstick), then it will find it there and stop.

So there you have it, javascript inheritance from the inside out. I hope you found it helpful.

If you read nothing else, read this!

I'll close with a fun story about Bruce Campbell, star of the Evil Dead universe. In the late 90's I had a buddy that worked at Activision. At the time they were rebooting Pitfall on the PlayStation and they tapped old Bruce to be the voice of Pitfall Harry. Back then, having live voice acting in video games was considered novel (sometimes to hilarious effect). One day my buddy was walking down the hall at Activision and who should he see coming the other direction but Bruce Campbell himself! My friend does a double take and utters "No way!" to which Bruce replies "In a big way baby!".

God bless that man.


Recent Posts
Archive