5 min read

Prototypes and Inheritance

Recently I had the unique pleasure of presenting at General Assembly Melbourne, I was asked to share what I knew about Prototypal Inheritance and would like to now share that with you and dive a bit deeper into some examples.

What is Prototypal Inheritance

Prototypal Inheritance can be succinctly described as objects without classes, and prototype delegation, also known to some of us as OLOO if you've been keeping up with the latest articles about JavaScript.

OLOO | Objects Linking to Other Objects

Isn't that just OOP?

You might ask this question after someone starts to describe Prototypes the first time, and you wouldn't be wrong in your assumption either.

OOP | Object Oriented Programming

But in JavaScript we call OOP Classical in terms of Inheritance.

How is Classical OOP different?

Classical and Prototypal Inheritance are fundamentally and semantically distinct. In Prototypal Instances inherit from other instances through concatenative inheritance which is literally OLOO and the purest form of OOP. But in Classical this is simply not the case.

Objects in JavaScript

Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects.

We don't need classes to make lots of similar objects.

You can introduce new functionality to native Objects in the same manner as your own Object definitions, without the need of creating a cloned instance of the native object or even extending a new object instance from the native one. In JavaScript all Objects are the same native or otherwise.

All variables, function, and data types in JavaScript excluding undefined null NaN Infinity which are more keywords anyway expose their prototypes.

Definitions and Instances of Objects

In classical OOP languages you will note that an object is first defined but until it has been instantiated the only functionality it provides is through static declarations which in itself still requires defining before access to its functionality is possible.

In JavaScript we still have both definitions and Instances yet all functionality is available directly within the definition without it ever being instantiated.
In fact, the idea of instantiating an Object instance is strictly not Prototypal at all in terms of the paradigm.

Constructors

There are no constructors in JavaScript, and before you leave a comment correcting this statement let me extend on that.
The internals implements a process called a constructor and that method can be inspected but it cannot be accessed, overridden or extended at all. It is completely not possible to write javascript that will execute in the native constructor.

One would also argue or link to articles on the internet that demonstrate JavaScript constructor examples, but these are not constructors in anything but a label given to the code they emulate. They are in fact nothing more than the humble function being executed when an object definition is invoked with the new keyword.

This is not a JavaScript constructor, it is merely coding like a constructor in JavaScript

The key to writing good Prototypal Inheritance is to avoid using the new keyword entirely as this process does not demonstrate the use of prototypes in any way and is essentially just following classical OOP paradigm.

If you’re creating constructor functions and inheriting from them, you haven’t learned JavaScript.

How pseudo constructors work

Consider

function Func() {
  // code stuff
}
var func = new Func();

Produces a new object that inherits from Func.prototype which can be accessed from the func variable.

The new keyword is used to invoke a constructor-like function.

What it actually does is;

  • Create a new instance
  • Bind this to the new instance
  • Allows instanceof to check whether or not an object’s prototype reference is the same object referenced by the .prototype
  • Names the object type after the constructor, which you’ll notice mostly in the debugging console. You’ll see [Object Foo], for example, instead of [Object object]

Extending this example to see how it is problematic

function Obj() {
    /* do your constructor things here */
    return this;
}
Obj.prototype.foo = function() {
    return '"said foo"'
}
Obj.prototype.bar = function() {return '"said bar"'}
var obj = new object();
obj.foo();
// > "said foo"
obj.bar();
// > "said bar"
Obj.foo()
// > Uncaught TypeError: Obj.foo is not a function

Notice the TypeError ?
Try without using new ;

var obj = Obj();
// > Uncaught TypeError: obj.set is not a function

so, is obj = undefined ???

 obj
// > window

obj = window !?!

WHERE DID WINDOW COME FROM

We attempted to simulate a constructor but in our simulated constructor we referenced this in an attempt to return the object properties, this would allow the variable holding the instance the ability to access said properties. Using new is the flaw. Objects in JavaScript are already accessible, using new changes that as described earlier.

Using new is the flaw.

But we can still handle it if we wanted to;

var Obj = function() {
  if (this === window)
    return new Obj(arguments);
  return this;
};

Now you have a constructor in JavaScript that will work as intended whether you invoke its properties directly or via an instance invoked using new no matter what.

This is getting complicated, and we haven't even yet added functionality, and any additional methods are now constrained.

Want to repeat this for all object definitions?

DRY | Don't Repeat Yourself

Namespace

Namespacing is a technique employed to avoid collisions with other objects or variables in the global scope.

JavaScript doesn't have built-in support for namespaces like other languages provides, it does have closures which can be used to achieve a similar effect to namespacing.

A closure is a function which remembers its environment in which it was created.
So, we'll use a self-executing anonymous function that exports an object definition to its namespace.

(function(){ // private area, away from the global scope
  var privateProp = function(){
    if (this === window)
      return new privateProp(arguments);
    return this;
  };
  privateProp.prototype.get = function(key){
    return this[key];
  };
  privateProp.prototype.set = function(key, value){
    this[key] = value;
    return this;
  };
  window.mynamespace = privateProp;
})();

If you run this you will notice that you cannot access privateProp in your console, it is now only accessible via window.mynamespace or simply mynamespace when in the global scope.

Prototypes In Practice

I mentioned before that you can introduce new functionality to native Objects in the same manner as your own Object definitions, here is a simple example.

Number.prototype.multiplyBy = function (number) {
  return this * number;
}

Test it;

(123).multiplyBy(2)
// > 246

Storing object instances without the new keyword

if (typeof Object.create !== 'function') {
    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
myQuery = Object.create(jQuery);

The Object.create function untangles JavaScript's constructor pattern.

It takes an existing object as a parameter and returns an empty new object that inherits from the old one.

If we attempt to obtain a member from the new object, and it lacks that key, then the old object will supply the member.

Now add functionality through Prototypal Inheritance to your own Object definitions.

var definition = {
  init: function(){},
  get: function(){},
  set: function(){}
};
myObject = Object.create(definition);

Objects inherit from objects. I love Prototypal JavaScript.

Conclusions

Avoid new - use .prototype

Both constructors and namespaces are paradigms of classical inheritance not Prototypal Inheritance.

Always use Prototypal Inheritance over Classical OOP

Douglas Crockford; the most experienced JavaScript programmer renown for being the first to publish methods of Classical OOP in JavaScript has himself stated he was wrong to to do so all along.

You will have to make mistakes to learn how to fix them.

If you’re creating constructor functions and inheriting from them, you haven’t learned JavaScript.

Enjoyed this?

If you made it here I would love to hear what you thought of the article.