JavaScript Prototypal Inheritance Explained

Image for post
Image for post
Photo by Frédéric Perez on Unsplash

When I first switched from Ruby to JavaScript, I found it challenging to grasp the concept of object prototype and the prototypal chain. The class keyword introduced in ES2015 is simply a syntactical sugar and does not make it easier to understand.

Yet regardless prototype-based or class-based, the reason to have chain or method resolution order (in Python) is to establish connections among classes and better use the inheritance relationship.

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property called prototype object, which acts as a template object that it inherits methods and properties from another object (like the __mro__ in Python). That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain. Before null is reached the second to last stop should be Object, as nearly all objects in JavaScript are instances of Object .

How is this working? Well, let’s look at an example.

Right now:

o.[[Prototype]] has properties b and c, and

o.[[Prototype]].[[Prototype]]is Object.prototype, and

o.[[Prototype]].[[Prototype]].[[Prototype]] is null.

So the whole property chain looks like:

Note that {a: 1, b: 2} are object f’s own properties that are not inherited from anywhere else.

When we try to access o.b we get value 2 . Why not 3 ?Because .b exists as f own property, and if it is defined, then the value is read and the prototype chain walk stops here. Even the prototype also has a b property, but it's not visited. This is called Property Shadowing.

Let’s look at a more concrete example on walking up the chain of prototypes.

As seen above, the __proto__ of doSomeInstancing is doSomething.prototype.

When you access a property of doSomeInstancing, the browser first looks to see if doSomeInstancing has that property.

If doSomeInstancing does not have the property, then the browser looks for the property in the __proto__ of doSomeInstancing (a.k.a. doSomething.prototype).

If the __proto__ of doSomeInstancing does not have the property, then the browser looks for __proto__ of the __proto__ of doSomeInstancing, in this case window.Object.prototype.

If the property is not found, then the __proto__ of the __proto__ of the __proto__ of doSomeInstancing is looked through, in which case null.

But __proto__ does not exist on null. So the result undefined is returned.

Image for post
Image for post

In short, prototype is a property of a Function object. It is the prototype of objects constructed by that function.

__proto__ is internal property of an object, pointing to its prototype.

When JavaScript executes this code, it adds prototype property to example, prototype property is an object with two properties to it:

So when we do example.prototype it returns

Now as you can see constructor is nothing but the function example itself and __proto__ points to the root level Object of JavaScript.

In above line we create an instance of example . How it works?

  • It first creates an empty new object {}
  • It creates __proto__ on myExample and makes it point to example.prototype so myExample.__proto__ === example.prototype
  • It executes example.prototype.constructor (which is definition of function example ) with the newly created empty object as its context (this), so the x,y property gets added to newly created object.
  • It returns newly created object

There are different ways to create create objects and the resulting prototype chain.

  • Objects created with syntax constructs
  • With a constructor

A “constructor” in JavaScript is “just” a function that happens to be called with the new operator.

  • With Object.create

ECMAScript 5 introduced a new method: Object.create(). Calling this method creates a new object. The prototype of this object is the first argument of the function:

  • With the class keyword

ECMAScript 2015 introduced a new set of keywords implementing classes. The new keywords include class, constructor, static, extends, and super.

Be careful with accessing or modifying prototype.

Note that the __proto__ is considered depreciated. You should use the following methods if possible.

  • Object.create(proto, [descriptors]) — creates an empty object with given proto as [[Prototype]] and optional property descriptors.
  • Object.getPrototypeOf(obj) — returns the [[Prototype]] of obj.
  • Object.setPrototypeOf(obj, proto) — sets the [[Prototype]] of obj to proto.

But don’t modify the prototype of an object on the fly if possible as it should only be generated when the object is created. JavaScript engines are highly optimised for this. Changing the prototype in the later stage will break the internal optimisations for object property access operations.

That’s pretty much of it today!

Happy Reading!

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store