DEV Community

Cover image for πŸŽ‰πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§ JavaScript Visualized: Prototypal Inheritance
Lydia Hallie
Lydia Hallie

Posted on

πŸŽ‰πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§ JavaScript Visualized: Prototypal Inheritance

Ever wondered why we can use built-in methods such as .length, .split(), .join() on our strings, arrays, or objects? We never explicitly specified them, where do they come from? Now don't say "It's JavaScript lol no one knows, it's magic πŸ§šπŸ»β€β™‚οΈ", it's actually because of something called prototypal inheritance. It's pretty awesome, and you use it more often than you realize!

We often have to create many objects of the same type. Say we have a website where people can browse dogs!

For every dog, we need object that represents that dog! πŸ• Instead of writing a new object each time, I'll use a constructor function (I know what you're thinking, I'll cover ES6 classes later on!) from which we can create Dog instances using the new keyword (this post isn't really about explaining constructor functions though, so I won't talk too much about that).

Every dog has a name, a breed, a color, and a function to bark!

When we created the Dog constructor function, it wasn't the only object we created. Automatically, we also created another object, called the prototype! By default, this object contains a constructor property, which is simply a reference to the original constructor function, Dog in this case.

The prototype property on the Dog constructor function is non-enumerable, meaning that it doesn't show up when we try to access the objects properties. But it's still there!

Okay so.. Why do we have this property object? First, let's create some dogs that we want to show. To keep it simple, I'll call them dog1 and dog2. dog1 is Daisy, a cute black Labrador! dog2 is Jack, the fearless white Jack Russell 😎

Let's log dog1 to the console, and expand its properties!

We see the properties we added, like name, breed, color, and bark.. but woah what is that __proto__ property! It's non-enumerable, meaning that it usually doesn't show up when we try to get the properties on the object. Let's expand it! πŸ˜ƒ

Woah it looks exactly like the Dog.prototype object! Well guess what, __proto__ is a reference to the Dog.prototype object. This is what prototypal inheritance is all about: each instance of the constructor has access to the prototype of the constructor! 🀯

So why is this cool? Sometimes we have properties that all instances share. For example the bark function in this case: it's the exact same for every instance, why create a new function each time we create a new dog, consuming memory each time? Instead, we can add it to the Dog.prototype object! πŸ₯³

Whenever we try to access a property on the instance, the engine first searches locally to see if the property is defined on the object itself. However, if it can't find the property we're trying to access, the engine walks down the prototype chain through the __proto__ property!

Now this is just one step, but it can contain several steps! If you followed along, you may have noticed that I didn't include one property when I expanded the __proto__ object showing Dog.prototype. Dog.prototype itself is an object, meaning that it's actually an instance of the Object constructor! That means that Dog.prototype also contains a __proto__ property, which is a reference to Object.prototype!

Finally, we have an answer to where all the built-in methods come from: they're on the prototype chain! πŸ˜ƒ

For example the .toString() method. Is it defined locally on the dog1 object? Hmm no.. Is it defined on the object dog1.__proto__ has a reference to, namely Dog.prototype? Also no! Is it defined on the object Dog.prototype.__proto__ has a reference to, namely Object.prototype? Yes! πŸ™ŒπŸΌ

Now, we've just been using constructor functions (function Dog() { ... }), which is still valid JavaScript. However, ES6 actually introduced an easier syntax for constructor functions and working with prototypes: classes!

Classes are only syntactical sugar for constructor functions. Everything still works the same way!

We write classes with the class keyword. A class has a constructor function, which is basically the constructor function we wrote in the ES5 syntax! The properties that we want to add to the prototype, are defined on the classes body itself.

Another great thing about classes, is that we can easily extend other classes.

Say that we want to show several dogs of the same breed, namely Chihuahuas! A chihuahua is (somehow... 😐) still a dog. To keep this example simple, I'll only pass the name property to the Dog class for now instead of name, breed and color. But these chihuahuas can also do something special, they have a small bark. Instead of saying Woof!, a chihuahua can also say Small woof! πŸ•

In an extended class, we can access the parent class' constructor using the super keyword. The arguments the parent class' constructor expects, we have to pass to super: name in this case.

myPet has access to both the Chihuahua.prototype and Dog.prototype (and automatically Object.prototype, since Dog.prototype is an object).

Since Chihuahua.prototype has the smallBark function, and Dog.prototype has the bark function, we can access both smallBark and bark on myPet!

Now as you can imagine, the prototype chain doesn't go on forever. Eventually there's an object which prototype is equal to null: the Object.prototype object in this case! If we try to access a property that's nowhere to be found locally or on the prototype chain, undefined gets returned.


Although I explained everything with constructor functions and classes here, another way to add prototypes to objects is with the Object.create method. With this method, we create a new object, and can specify exactly what the prototype of that object should be! πŸ’ͺ🏼

We do this, by passing an existing object as argument to the Object.create method. That object is the prototype of the object we create!

Let's log the me object we just created.

We didn't add any properties to the me object, it simply only contains the non-enumerable __proto__ property! The __proto__ property holds a reference to the object we defined as the prototype: the person object, which has a name and an age property. Since the person object is an object, the value of the __proto__ property on the person object is Object.prototype (but to make it a bit easier to read, I didn't expand that property in the gif!)


Hopefully, you now understand why prototypal inheritance is such an important feature in the wonderful world of JavaScript! If you have questions, feel free to reach out to me! 😊

✨ Twitter πŸ‘©πŸ½β€πŸ’» Instagram πŸ’» GitHub πŸ’‘ LinkedIn πŸ“· YouTube πŸ’Œ Email

Latest comments (100)

Collapse
 
porobertdev profile image
Robert P.

Thank you Lydia! πŸ™‚

Very good article, easy to follow along and understand. This helped solidifying the knowledge I've previously learned before being linked here, but I've also got a rough idea on classes now. Classes seemed so weird until now πŸ˜‚

Nice gifs too!

I can't wait to read your other articles.

Collapse
 
mohamedhesham1 profile image
Mohamed Hesham

amazing article

Collapse
 
adrianadamz profile image
Adrian Adam Ε»ywno

You've done a beautiful job at taking a complicated topic and making it easy to digest. Your visualizations and brevity allow for this. Many thanks!

Collapse
 
phatsss profile image
phatsss

i really love your Gifs lolz

Collapse
 
lightningwind profile image
David Islam

Well explained!

Collapse
 
prafulla-codes profile image
Prafulla Raichurkar

Wow! This explanation makes it crystal clear

Collapse
 
perez11abel profile image
perez11abel

The amount of YouTube videos and articles I've read and I could not understand prototypes. I really enjoyed Your article. Everything was super clear and concise and made the most since for me (a beginner.)

Collapse
 
endzelisp profile image
Armando Endzelis

Hi there.. Exist a difference between using:

me = Object.create(person) and,
me.prototype = Object.create(person.prototype)

Thank you for your great tutorial.

Collapse
 
devvsakib profile image
Sakib Ahmed

great!!!!!!!!! describing was easy

Collapse
 
dvakatsiienko profile image
Dima Vakatsiienko

Hi! How do you create such a cool looking pictures with diagrams and animations?

Collapse
 
dvakatsiienko profile image
Dima Vakatsiienko

hello!
how do you create such a cool looking animations and disagrams?

Collapse
 
codingfunky profile image
CodingFunky

This really helped me understand the concepts :)

Collapse
 
alonedatascientist profile image
alonedatascientist

Very helpful. Thank you.

Collapse
 
mat3uszkek profile image
Mateusz SkrobiΕ›

"A chihuahua is (somehow... 😐) still a dog." hahaha :D Great article btw!!!! <3

Collapse
 
thorondormanwe profile image
Carlos Rangel

I came here guided by the Odin Project, and your explanation is really clear and concise. Thanks :)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.