JavaScript Inheritance

Ben Aston
6 min readNov 17, 2014

--

Or, Why Classes Are Unnecessary.

JavaScript has a style of inheritance — prototypical — that stems partly from Brendan Eich’s genius, and partly from the ridiculous time constraints he was under when designing the language. Legend has it he developed JavaScript inside ten days in 1995.

Prototypical inheritance says that object instances inherit from other object instances. This differs from inheritance in class-based languages, where inheritance linkages are made at the class level before instantiation, and instantiations create a single object that has the characteristics of both the parent and child classes.

When Eich designed JavaScript, he took inspiration from Self. This in turn was an attempt to refine Smalltalk (the first fully object-oriented language) via the removal of classes.

So JavaScript started life without classes. And this required a more essential type of inheritance that, although simpler than class-based inheritance, is harder to describe because the only concepts available for explanatory purposes are objects and functions.

Beginnings

Let’s start with a very simple piece of code:

function F() {}

At this point most developers starting with JavaScript will say, “OK, make that inherit from something else”. Unfortunately this request stems from an incomplete understanding of JavaScript.

By the way, I will mostly use the term “function-object” here to highlight the fact that functions are also objects (they are instances of the built-in Object).

The above code brings into being an instance of the built-in Function function-object. i.e. “it creates a function”. In broad-terms, this is the inheritance relationship for a function-object:

F => Function => Object

The arrows (=>) above represent a reference-chain (the prototype chain) that defines the inheritance relationship for an object. This is a chain of references stored in private (I’ll return to this) properties called [[Prototype]] (yes, those brackets are part of the name). Hence, we cannot change the inheritance relationship for F itself.

So the demand “make F inherit from something else” doesn’t make a great deal of sense. The inheritance relationship for function-object F is established already and cannot be changed with the facilities made available by JavaScript.

What we can do is affect the inheritance chain for objects created by F.

And this, it turns out, is what you as a developer actually need.

Now, I’ll caveat all this by saying that the above is how you should think of the situation for most purposes. This is JavaScript after-all, and so it is actually possible to change the inheritance hierarchy after creation of a function object by using the Object.setPrototypeOf function provided in ECMAScript 6 (or even by assigning a value to the non-standard __proto__ property exposed in some browsers), although doing so is “strongly discouraged” according to Mozilla. Regardless, changing the internal [[Prototype]] of an object directly is likely to cause more confusion than benefit in the vast majority of situations.

The source of confusion

There is a famous lightning talk from “Codemash 2012" delivered by Gary Bernhardt entitled Wat that highlights a number of perceived inconsistencies in JavaScript. Now we can debate the merits of this talk, but one thing is certain, Bernhardt missed by far and away the biggest JavaScript “Wat” of all: JavaScript has two different properties — each of critical importance — used for different purposes, at different times, distinguished only by the absence or inclusion of brackets and a capitalization.

The two properties are:

  1. [[Prototype]] and,
  2. prototype

Yes, you read that right. The first is called [[Prototype]] with two sets of square brackets around it. The second is simply called prototype (i.e. just the word “prototype”). Both are different. Both are lazily called “the prototype”. Cue deep-seated confusion.

Let’s put down some definitions:

The prototype is a property found only on function-objects. Developers can manipulate this property to control what objects created by the function inherit from. By default a plain-old instance of Object is created behind the scenes (with its constructor set to be a reference to the function-object just created).

The [[Prototype]] is a reference to the object pointed at by the prototype (note, no brackets) property of the function-object used to create the object.

Back to the beginning

Let’s circle back.

function F() {}

What is going on when this is evaluated by the interpreter? Well, behind the scenes the built-in Function function-object is being invoked as a constructor (in reality something different, but equivalent, occurs). The Function function-object looks like this:

function Function(argName1, …argNameN, body) { … }

Per our earlier definitions, this function returns an object F with its [[Prototype]] set to the prototype of the built-in Function function-object (EmptyFunction in Chrome). i.e.:

F instanceof Function === true

And its prototype is set to a plain-old instance of the built-in Object function-object (i.e. objects created by F will have this object instance on their prototype chain).

Its constructor is set to the Function function-object itself, because that is the function-object that created it.

In diagram form it looks something like this:

Update (July 2016): the diagram above sh0ws a prototype property on Function.prototype. This is erroneous. There is no prototype property on Function.prototype. This is the only function to my knowledge that does not have this property.

Some things to note:

  1. It’s more complicated than you probably imagined.
  2. The distinction between plain-old object instances and function-object instances is important.
  3. Everything in JavaScript is an object instance (apart from some clever optimizations for primitive values that you don’t need to worry about here).
  4. Yes, even function-object instances (aka. functions) are objects.
  5. Not everything is a function in JavaScript. So in some sense, JavaScript is more object-oriented than functional.
  6. When Brendan Eich wrote JavaScript he included a constructor property that, by default, is set to point to the function-object instance that created the object instance. This property can be ignored, but provides useful metadata and speaks to the intent of the language author. I believe the constructor property is much neglected and serves a useful purpose. It is particularly helpful when attempting to understand the runtime state of an application. In some sense, the constructor property can be used to help us identify the closest “abstract data type” the object is an instance of. JavaScript may be loosely typed, but that doesn’t mean we need to ignore types altogether.
  7. Only function-objects have the prototype (note, no square brackets) property. Repeat this until you are blue in the face. The function-objects in the earlier diagram are: F, Function and Object. Function and Object are built-in. That is they are provided by the runtime environment. F is a custom function-object we just created.
  8. All objects (i.e. everything — remember, everything is an object (with the caveat previously mentioned)) have a [[Prototype]] property. Even the root object instance (i.e. the object instance at the top of the object graph) has a [[Prototype]] — although it is null. It is null because we have to stop the prototype chain somewhere.
  9. …And this highlights the difference between null and undefined. Null is the null-object. Undefined represents a lack of something. Null is something. Undefined is a marker.

Summary

Inheritance in JavaScript is complicated because the language does not supply us with useful high-level constructs with which to describe things.

Everything is an object — and that makes descriptions sound “circular”. When you truly understand JavaScript you appreciate that this essential nature of JavaScript is not a flaw, but an asset. Why complicate the language with another keyword like “class” when functions are all you need? Classes add only complexity.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.

Unfortunately the volume of your voice does not correlate with your level of comprehension. Many developers look at JavaScript and say “Well, duh! It needs classes!”. So much so that classes have been added to ECMAScript 6.

Hopefully you can see from this post that this addition is counter to the original minimalist spirit of the language.

More languages should have been developed in ten days or less.

My name is Ben Aston and thank you for reading my post today. I am a JavaScript consultant, based in London, available for short-term consultancy globally. I can be contacted at ben@bj.ma.

If you would like to further develop your knowledge of JavaScript you might be interested in my hands-on training course. Full details can be found online at www.learnjavascript.london.

If you enjoyed this piece, please let me know by clicking the “recommend” button below.

You might also be interested in my post on closures in JavaScript.

Made in the United Kingdom

--

--