A Guide To Prototype-Based Class Inheritance In JavaScript

Two properties magically appear in our class definition: constructor and prototype.

constructor.

They do not point to the same object.

Let’s break them down:Let’s say we define a new class Crane (using either function or class keyword.

)A custom constructor we just created is now attached to the prototype property of our custom Crane class.

It’s a link that points to its own constructor.

It creates circular logic.

But that’s only one piece of the puzzle.

Let’s now take a look at Crane.

constructor:Crane.

constructor itself points to the type of the object it was created from.

Because all object constructors are natively functions, the object Crane.

constructor points to is an object of type Function, in other words the function constructor.

(In JavaScript functions can be used as object constructors but they are also objects at the same time, once instantiated.

)This dynamic between Crane.

prototype.

constructor and Crane.

constructor is what enables prototype inheritance at molecular level.

You rarely even have to think about this when writing JavaScript code.

But this is definitely an interview question.

Let’s briefly go over this again.

Crane.

prototype.

constructor points to its own constructor.

It’s almost like saying ”I am me.

”Same exact thing happens when you define a class using class keyword:But, the Crane.

constructor property points to Function constructor.

And that’s how the link is established.

Now Crane object itself can be the ”prototype” of another object.

And that object can be prototype of another object.

And so on.

The chain can go on forever.

Side Note: In the case of the ES5-style functions, the function itself is theconstructor.

But ES6 class keyword places constructor inside of its scope.

Thisis just a syntactic difference.

Prototype-Based InheritanceWe should always use class and extends keywords to create and inherit objects.

But they are only candy wrapper for what actually goes on behind the scenes.

Even though creating object inheritance hierarchies using ES5-style syntax is long outdated and rarely seen among professional software developers, by understanding it you will gain a deeper insight into how it actually works.

Let’s define a new object Bird and add 3 properties: type, color and eggs.

Let’s also add 3 methods: fly, walk and lay_egg.

Something all birds can do:Note that I intentionally grayed out the lay_egg method.

Remember how wediscussed earlier that Bird.

prototype points to its own constructor?That means there is no difference between attaching methods using this keyword inside Bird and simply adding it directly to the Bird.

prototype property.

You could have alternatively attached the lay egg method directly to Bird.

prototype as shown in the next example:The code above is equivalent to what we’ve done in Bird class when we defined lay egg method on the this object reference.

It’s up to you how you want to do this.

I personally prefer defining methods inside the function itself.

Not All Birds Are Made AlikeThe whole point of object inheritance is to use one common class that defines all properties and methods that all children of that class will automatically inherit.

This makes code shorter and saves memory.

(Imagine defining the same properties and methods on all of the children objects individually all over again.

It would take twice as much memory.

)Let’s create several different types of birds.

Even though all of them can still fly, walk and lay_eggs (because they are inherited from main Bird class,) each unique bird type will add its own methods unique to that class.

For example, only parrots can talk.

And only raven can solve puzzles.

Only a songbird can sing.

ParrotLet’s create a Parrot and inherit it from Bird:Parrot is a regular constructor function just like Bird.

The difference is that we call Bird’s constructor with Bird.

call and pass the Parrot’s this context, before attaching our own methods.

Bird.

call simply adds all of its properties and methods to Parrot.

In addition to that, we are also adding our own method: talk.

Now parrot can fly, walk, lay eggs and talk!.But we never had to define fly walk and lay_eggs methods inside Parrot itself.

RavenIn the same way, let’s create Raven and inherit it from Bird:Ravens are unique in that they can solve puzzle.

SongbirdNow, let’s create Songbird and inherit it from Bird:Songbirds can sing.

Testing The BirdsWe just created a bunch of different birds with unique abilities.

Let’s see whatthey’re capable of!.Up until now we only defined classes and established theirhierarchical relationship.

In order to work with objects we need to instantiate them:Let’s instantiate a sparrow using the original Bird constructor:Sparrow can fly, walk and lay eggs, because it was inherited from Bird that defines all those methods.

But a sparrow cannot talk.

Because it is not a Parrot.

Let’s create a parakeet from Parrot class:Because Parrot is inherited from Bird, we get all of its methods.

A parakeet has the unique ability to talk, but it cannot sing!.The sing method is available only on objects of type Songbird.

Let’s inherit starling from Songbird class:Finally, let’s create a raven and solve some puzzles:Using class and extends keywordsThe ES5-style constructors can be a bit cumbersome.

Luckily we now have class and extends keywords to accomplish exactly the same thing we just did in the previous section.

class replaces functionextends and super() replace Bird.

call from previous examples.

Note we must use super() which calls the constructor of the parent class.

This syntax looks a lot more manageable!Now all we have to do is instantiate the object:OverviewClass inheritance helps establish a hierarchy of objects.

Classes are the fundamental building blocks of your application design and architecture.

They make working with code a bit more human.

Of course, Bird was just an example.

In a real-world scenario, it could be anything based on what type of application you’re trying to build.

Vehicle class can be a parent of Motorcycle, Car, or Tank.

Fish can be used to inherit Shark, Goldfish, Pike and so on.

Inheritance helps us write cleaner code and re-purpose the parent object to save memory on repeating object property and method definitions.

.. More details

Leave a Reply