11 July 2016

JavaScript OOP inheritance explained with diagrams


We're not talking about ES6 classes today.  Just ES5 JavaScript object-oriented programming.

## Prototypal inheritance

People say there's at least these **3 big features of OOP** that distinguishes OOP from other styles of programming:

1. Encapsulation
2. Polymorphism
3. Inheritance

We're going to focus on the last item today.

OOP in JavaScript isn't intrinsically class-based in the style of Java.  I assume you already know a thing or two about OOP in terms of Java or Python, or similar though.

Instead, **JavaScript OOP is prototype based**.

That means you'd just make an object `c` as you like it, no class definition required --- but if you must think in classes, imagine making a class `C` and using it to create exactly the one object `c`.

Then when you want another object `s` to inherit from object `c`, you'd just do it, *no class required* --- again if you must, imagine making a class `S` that inherits from `C`, and using `S` to create exactly the one object `s`.

Conceptually, it's simple, but trying to use it productively, with constructors and everything else, and it can get confusing.

Rather than learning how to do class-based OOP in JavaScript (for that, see MDN's [Introduction to Object-Oriented JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript) instead), let's try to really understand what JavaScript is doing --- from the bottom up.

## Diving in, bottom up

In JavaScript, everything are objects, even functions.

OK, some things are primitives... forget that, let's just see some code.

By the way, I'm running all the code in the Firefox Console.  Explanations and diagrams are interwoven into the code as comments.

## Cosmic Super Object
Let's start with the "cosmic super" object that all objects
usually inherit from, namely the object stored at 
`Object.prototype`.

```JavaScript
typeof(Object.prototype); // is an object

Object.prototype.prototype === undefined; // true
Object.prototype.__proto__ === null; // true
```

So `Object.prototype` doesn't have a `prototype`, and it doesn't
"`__proto__`-inherit" from anything.  The buck stops here.

In JavaScript, each object `o` has a `__proto__` property that
points to the object that `o` **prototypely-inherits** from
(as opposed to "inherit" in the class-based sense).

So from here on, if `s.__proto__ === k` then we say `s` **proto-inherits** from `k`.  I use the term "proto-inherit" to distinguish from the Java-style, class-based, concept of inheritance.

Yes, `__proto__` is deprecated, but it works (for now) and is easier to think with.


We're going to start diagram out the relationship
between the various objects we're exploring in JavaScript.

![Object.prototype UML-like diagram](//3.bp.blogspot.com/-GsKwMJquGoU/V6U1ryKc_KI/AAAAAAAADAU/bUL2g3b-mJI5oZN6rkhtNleQ1bOh6ZolwCLcB/s1600/d1.txt.png)

As described before, if you must think in classes, then making an object
in JavaScript is like writing a class and instantiating exactly one object
from it, so we'll draw objects in the style of UML classes.

i.e.

![UML-like class diagram example schema](//4.bp.blogspot.com/-aAt26sbiz44/V6U2gc07Q8I/AAAAAAAADAc/EZbu4ugVDYc5KON_6vS97Jlqa7McCMxpgCLcB/s1600/d2.txt.png)


## Object function
But if `Object.prototype` is an object, what is `Object`?

```JavaScript
typeof(Object); // is a function.
```

Huh, but it had a `prototype` property before...
I guess functions are like objects and can have properties.

In fact, there is a circular relationship between
`Object` and `Object.prototype`:

```JavaScript
Object.prototype.constructor === Object; // true
```

Since functions can have properties, we'll draw them like objects
but tag them with "fn:"

![Circular relationship between fn Object and Object.prototype](//4.bp.blogspot.com/-kSLgDPLfS8I/V6U2qcTmy_I/AAAAAAAADAw/7mofOGFZtTIhhq9MswZ01JGOflL55VrEwCLcB/s1600/d3.txt.png)

There's a general circular relationship between functions and prototype
objects as we'll soon see.


## Function function
Since `Object` is a function, what is `Function`?

```JavaScript
typeof(Function); // is also a function
```

Actually, `Function` is very much like `Object` with a
circular relationship:

```JavaScript
Function.prototype.constructor === Function; // true
```

But what is `Function.prototype`?

```JavaScript
typeof(Function.prototype); // is a function
```

So there's a general circular relationship between functions and prototype objects as well:

![Circular relationship between fn Function and Function.prototype](//4.bp.blogspot.com/-6OC7qepxVFs/V6U2qRXrF2I/AAAAAAAADA0/KF3w5YAc0QQkupmVK5eHNNZHDjLE7gmEACLcB/s1600/d4.txt.png)


## How do Function and Object relate?
Well we already know `Object` and `Function` are both functions.
Now observe where they proto-inherit from:

```JavaScript
Object.__proto__ === Function.prototype; // true
Function.__proto__ === Function.prototype; // true
```

Wasn't `Function.prototype` a function as well? Yes and no...

```JavaScript
typeof(Function.prototype); // recall that's a function
Function.prototype.__proto__ === Object.prototype; // true
```

![Circular relationship between fn Object and Object.prototype, and between fn Function and Function.prototype](//3.bp.blogspot.com/-qQINP6LErzc/V6U2qgcqIeI/AAAAAAAADA4/vqj7UmDXCCwlhLYVL5Wu994-gurau7_FACLcB/s1600/d5.txt.png)

So the buck stops at `Object.prototype`, and `Function.prototype` is
a function but proto-inherits from `Object.prototype`.

`Object` and `Function` are both more straightforward:
both are functions and proto-inherits from `Function.prototype`.


## Literal objects and functions
Consider the following literal object and function:

```JavaScript
var x = {};
typeof(x); // is an object

var f = function(){};
typeof(f); // is a function
```

So what do they proto-inherit from?

```JavaScript
x.__proto__ === Object.prototype; // true
f.__proto__ === Function.prototype; // true
```

...they proto-inherit not from `Object` or `Function`, but from
`Object.prototype` or `Function.prototype`.

Remember the general circular relationship between functions and 
prototype objects? Well `x` is an object, so I suspect we won't
find it related circularly with its prototype object (if it has one)...

```JavaScript
x.prototype === undefined; // true
```

But `f` is a function, so let's see if it has a circular relationship
with its prototype object...

```JavaScript
typeof(f.prototype); // is an object
f.prototype.__proto__ === Object.prototype; // true
f.prototype.prototype === undefined; // true
f.prototype.constructor === f; // true, truly circular!
```

Thus we see the following relationship `x`, `f`, and the existing circular relationships between `Object`, `Function`, and their prototypes:

![Relationship between Object, Function, their prototypes, and object x and function f](//1.bp.blogspot.com/-su_u5BOAbCk/V6U2qoXFdOI/AAAAAAAADA8/IWrkxsSkRQcAhKxyFevFn_S_9U9sUQbAwCLcB/s1600/d6.txt.png)


## Let's start writing some "classes"
The goal here is to end up with a "super class" called `SuperKlass`, which will have as a "subclass" the class `Klass`.

```JavaScript
var SuperKlass = function(){}; // a constructor for our super "class".
typeof(SuperKlass.prototype); // is an object.

SuperKlass.__proto__ === Function.prototype; // true
SuperKlass.prototype.__proto__ === Object.prototype; // true

SuperKlass.prototype.constructor === SuperKlass; // true
```

So merely writing a function creates a circular relationship between
a function and an object:

![Relationship between Function.prototype and SuperKlass, and Object.prototype and SuperKlass.prototype.](//3.bp.blogspot.com/-yI4Q440D4R4/V6U2q8_xXxI/AAAAAAAADBA/zPOYk-i57AQyMmDbkeW7Fbff9xbnDNIzwCLcB/s1600/d7.txt.png)

We'll abbreviate our diagram of the `Function.prototype` and
`Object.prototype` objects.


```JavaScript
var Klass = function(){}; // a constructor for another "class"
```

As with the `SuperKlass` case above, we get this circular relationship:

![Relationship between Function.prototype and Klass, and Object.prototype and Klass.prototype.](//1.bp.blogspot.com/-mcLjA1-FoiY/V6U2qw9oENI/AAAAAAAADBE/7hC7Rc-mOTAQYvg98OVkTqn2APoSQLn6QCLcB/s1600/d8.txt.png)

`Klass` and `SuperKlass` don't look like classes, but they would if we started writing some methods for them.  But we'll hold of on that until we get some class-based inheritance going on first as those two are currently unrelated to each other.


## Proto-inherit our way to writing "subclasses"
The above don't look like classes yet, but they will once
we make `Klass` inherit from `SuperKlass`.

```JavaScript
var oldKlassProto = Klass.prototype; // for later testing

Klass.prototype = Object.create(SuperKlass.prototype);

Klass.prototype === oldKlassProto; // false. It's really a new object!

Klass.prototype.__proto__ === SuperKlass.prototype; // true
Klass.prototype.constructor === SuperKlass; // true
```

The `Object.create` line of code basically did the following:
create a new object `o` that proto-inherits
from `SuperKlass.prototype`, then set `o.constructor` to
the `constructor` of `SuperKlass.prototype`, which is of course
just `SuperKlass` because of the circular relationship we saw above!

Then we set `Klass.prototype` to `o` resulting in
this relationship:

![Relationship between Klass, Klass.prototype, SuperKlass, SuperKlass.prototype, and Object and Function prototypes, after using Object.create.](//2.bp.blogspot.com/-VXLOe-yd4Yw/V6U2rP1XdMI/AAAAAAAADBI/FwBmiFrwRGMiPhHngho5cQcHjsuDNBEDwCLcB/s1600/d9.txt.png)

Notice the `Klass.prototype.constructor` no longer points back to
`Klass`, breaking the circular relationship between constructor functions
and prototypes we kept seeing above.  Let's repair that...


```JavaScript
Klass.prototype.constructor = Klass;
```

![Relationship after repairing Klass.prototype.constructor to point to Klass](//2.bp.blogspot.com/-ejNBAnuIc5U/V6U2p-HNVOI/AAAAAAAADAg/DuxNC0nPid4LFZod9zOK4B94jC3zxWadwCLcB/s1600/d10.txt.png)

Now `Klass` is a subclass inheriting from `SuperKlass` --- inheriting,
not proto-inheriting.


## Instance method for our Klass and some new objects
Let's dynamically create a `SuperKlass` instance method:

```JavaScript
SuperKlass.prototype.hi = function(){return "super!"};
```

Notice where the method is created in the diagram and how it relates to `SuperKlass`, and `Klass`:

![Relationship after dynamically patching in a "hi" method in SuperKlass.prototype](//4.bp.blogspot.com/-zFnyN7lBJBo/V6U2qMcCBGI/AAAAAAAADAk/XdMgph8tQiYQQCXVzCoZReknZbeea3h8ACLcB/s1600/d11.txt.png)

We keep making classes but never instance objects constructed
from those classes, so let's do that now:

```JavaScript
var sk = new SuperKlass();
var k = new Klass();

sk.prototype === undefined; // true
k.prototype === undefined; // true. They really are just objects

sk.__proto__ === SuperKlass.prototype; // true
k.__proto__ === Klass.prototype; // true
```

So `new F()` just makes a fresh object that proto-inherits from
`F.prototype`.  In fact, it also runs the `F()` constructor function
on that fresh object so to initialize it by doing whatever `F` does.

![Relationship between k and Klass, and sk and SuperKlass.](//4.bp.blogspot.com/-jMTPckF9Nos/V6U2qEWn-5I/AAAAAAAADAo/hhesB__CMoERJ-KIOWjhCacpca2lDY21QCLcB/s1600/d12.txt.png)

## Polymorphism
"Polymorphism" here just means, if an object `k` has it, use it,
otherwise repeat looking for it with the object that `k` 
proto-inherits from (done recursively, again and again...).

```JavaScript
sk.hi(); // "super!"
```
...note that `sk` itself doesn't have a method `hi()`,
but `sk.__proto__` (a.k.a. `SuperKlass.prototype`) has it!

```JavaScript
k.hi(); // "super!" - polymorphic call to inherited method
```

`k` itself doesn't have `hi()`, but in this case,
`k.__proto__` (a.k.a. `Klass.prototype`) doesn't have it either!
But `k.__proto__.__proto__`  (a.k.a. `SuperKlass.prototype`)
does have it!

In effect we've got, in Java terms, an instance method `hi()`
defined in the `SuperKlass` class, and `Klass` inherits it being
a subclass.  So `k` is like an instance of the class `Klass`,
and `sk` is like an instance of the class `SuperKlass`...
even though JavaScript has no native concept of class or
class-based inheritance (not until ES6 anyway).

Let's write more methods, this time dynamically adding the `hi` method to `Klass.prototype`:

```JavaScript
Klass.prototype.hi = function(){return "klass!"};
```

Notice how this `hi` method relates to the `Klass.prototype` object, "overriding" the one proto-inherited from `SuperKlass.prototype`:

![Relationship after dynamically patching in a "hi" method in Klass.prototype](//4.bp.blogspot.com/-XBwF4BXZZkU/V6U2qUNvXsI/AAAAAAAADAs/bnY52xop18o7XTHwVX8CjcREqGevfU7OQCLcB/s1600/d13.txt.png)

```JavaScript
sk.hi(); // "super!"
k.hi(); // "klass!" - polymorphic call to overriding method
```

...of course `k` itself doesn't have a method `hi()`,
but `k.__proto__` (a.k.a. `Klass.prototype`) this time does!

Although JavaScript has no native concept of class or class-based 
inheritance (not until ES6), it kind of half-heartedly does since
ES3 (JavaScript 1.4) via the `instanceof` operator which basically
just checks to see if a function's `prototype` is proto-inherited by,
or is proto-inherited proto-inherited by, or is proto-inherited 
proto-inherited proto-inherited by, ..., the given object.

```JavaScript
sk instanceof Klass; // false
sk instanceof SuperKlass; // true
```

The last line evaluates to `true` because `sk` proto-inherits from `SuperKlass.prototype`

```JavaScript
k instanceof Klass; // true
k instanceof SuperKlass; // also true!
```

The last line *also* evaluates to `true` because `k` proto-inherits proto-inherits `SuperKlass.prototype`

Just follow the proto-inheritance hierarchy!


## this and super
Let's write another subclass.

```JavaScript
var Klass2 = function(nm){
    // super(); in Java terms
    SuperKlass.call(this); // call superclass's constructor
                           // with `this` object
    this.name = nm;
};
Klass2.prototype = Object.create(SuperKlass.prototype);
Klass2.prototype.constructor = Klass2;

// Klass2 inherits from SuperKlass via usual proto-inheritance hierarchy:
Klass2.prototype.__proto__ === SuperKlass.prototype; // true


// make a `Klass2` instance
var k2 = new Klass2("Pat");
k2.hi(); // "super!" - polymorphic call to inherited method


// define a `Klass2` instance method
Klass2.prototype.hi = function(){return this.name};

sk.hi(); // "super!"
k.hi(); // "klass!"
k2.hi(); // "Pat"
```

More or less, `this` refers to the object the method is called on, but technically
it gets tricky as JavaScript's concept of a method is really in terms of functions
that are stored as properties on objects.  For details, see [MDN's JavaScript reference of this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).

Notice the dynamicism of JavaScript, where we added a new instance method to an existing class, and all existing instance objects of that class got to use the newly defined instance method.  No recompilation needed, unlike e.g. Java.

## References
It was noted that `__proto__` is deprecated.  It was a way of exposing to 
us the internal linkages between JavaScript's internal representation of 
objects.  The "proper" way now is through using the `getPrototypeOf` method.
See [MDN's reference on Object.prototype.\_\_proto\_\_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto).

A more in-depth explanation of JavaScript OOP can be found at MDN's 
reference on [Inheritance and the prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) or at [Introduction to Object-Oriented JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript).

A hugely more in-depth explanation with beautiful diagrams is available at
[JavaScript: the core](http://dmitrysoshnikov.com/ecmascript/javascript-the-core).
Incidentally, had I found that article first, I might never have written
this one...

...because I wrote this to help myself understand JavaScript's prototypal OOP system
by drawing diagrams and playing around with JavaScript in the Firefox Console.
Conceptually, it was so simple, but then when you actually program with it,
or when you try to use it in a more class-based manner, it can get confusing.

All diagrams originally drawn with [ASCII Flow](http://asciiflow.com).  Diagrams turned into pretty PNG images using [Shaape](https://github.com/christiangoltz/shaape).

No comments: