All you need to know about Prototypal Inheritance — The second pillar of Javascript
Javascript pillars
This article is inspired by Andrei’s course https://www.udemy.com/course/advanced-javascript-concepts/
What we will learn here will help us understand Object-oriented programming(OOP).
In case you haven’t seen the first pillar>>>
Remember arrays and functions are just objects in Javascript.
It is because Javascript uses something called prototypal inheritance.
Inheritance is an object getting access to the properties and methods of another object.
From our diagram above, the array object gets access to the methods and properties of the object in Javascript — same with the function through this chain that we call prototypal inheritance.
Inheritance is an object getting access to the properties and methods of another object.
Let's look at arrays as an example:
By doing __proto__ we see that we get all the methods that arrays have. What happened is that I created a new array and our new array was created from what we call the Array constructor. This big array constructor created our array variable that contained an empty array. We did __proto__ to go up the prototype chain and get into the big array.
By that theory, if I go up the prototype chain once more, I should get an object.
By that theory, if I go up the prototype chain once more, I should get an object.
This is the object that everything in Javascript gets created from including functions and arrays.
We see that we have some properties on this object. For example toString method.
That means that everything that is a descendant of this object will get the toString method which means that even our array has a toString method because of this prototype chain.
As we said, an object gets access to the properties and methods of another object through the prototype chain.
Now let's look at functions
If we go up the prototype chain:
We get the native function. This is our base function where all functions are created. So that when I go up the prototype chain again, I get that base object.
And objects?
__proto__ gets us to the base object. Here I created my obj variable from that base object. obj has the prototypal chain to the base object
And this is what prototypal inheritance is.
This feature is quite unique from other languages such as C# or Java. They use something called Classical inheritance.
This feature is quite unique from other languages such as C# or Java. They use something called Classical inheritance. Javascript uses prototypal inheritance.
Javascript uses prototypal inheritance. And although in Javascript we do have the class keyword, this is what we call syntactic sugar. There are no classes in Javascript. We only have the prototypal inheritance.
The prototype chain
If I run this code:
Let's have another object. A weaker lizard without a lot of power.
Now suppose we wanted to borrow a method from the dragon object. How can we do that?
Previously, we have used bind() to borrow methods from an object.
With bind() we can do something like this:
So that when we run our code we see that we have a borrowed method from the dragon.
But let's say this object gets a little more complicated. Maybe for us to be able to breathe fire, we have to have the fire property set to true.
So that we can have a conditional statement before we can have our battle cry.
Unfortunately now our lizard doesn't have fire set to true. So our singLizard returns undefined even though we borrowed the method. We don't have the fire ability, so it's never going to sing I am kiki the breather of fire.
Now, of course, we could simply manually add the property, but you can see how that could get very complicated. Because what if we had a big object and we wanna borrow more than just one method? Maybe inherit a bunch of the dragon properties for the lizard as well?
This is where we use prototypal inheritance.
We could have a prototype chain that says hey, I want lizard to inherit all these properties and methods from dragon.
We can see that we have managed through our prototype chain to inherit the properties and methods from dragon except for the methods and properties that we have — name and fight; these stay the same.
And if we call something that dragon doesn't have? We get an error because we go up the prototype chain and find that dragon has no dance.
From there we go up the prototype chain of dragon again which is the original base object and there also there is no dance.
Note that this also means that I can use whatever methods that the base object has.
If for example, I use isPrototypeOf method on dragon which comes with the base object:
It works because we see that dragon is a prototype of lizard.
Our Javascript engine goes up the chain to the base object to use the functionality of isPrototypeOf.
Let's have our example again:
If I run this:
But as we mentioned earlier we can also use methods from the base object, for example, hasOwnProperty.
What we are saying here with hasOwnProperty is that only log what lizard has as its own property. Therefore, we only get name and fight — the other properties are inherited from up the prototype chain.
You can see that we are not copying these methods. Instead, Javascript automatically looks through the prototype chain to find these methods.
But you’re probably asking yourself why you haven’t seen this __proto__ before in code bases yet it seems pretty useful. Why isn’t it everywhere?
But you’re probably asking yourself why you haven't seen this __proto__ before in code bases yet it seems pretty useful. Why isn’t it everywhere?
Now although we have use this __proto__ to demonstrate here, you shouldn't really use it. It's bad for performance and there is a different way to inherit properties.
We never want to manually assign when we create the prototype chain and create that chain ourselves. It's going to mess up our Javascript compiler pretty badly.
We can properly do it with Object-Oriented Programming.
Why prototypal inheritance is useful
The fact that objects can share prototypes means that you can have objects that are pointed to the same place in memory thus being more efficient with our code.
Imagine if we had a lot of lizards and we just copied all this functionality of the dragon onto the lizard to a different place in memory. That can get overwhelming fairly soon. With prototypal inheritance, instead of copying all this to a different place in memory, we just have one reference.
With prototypal inheritance, instead of copying all this to a different place in memory, we just have one reference.
Anything that inherits from dragon will just use this one instance because the Javascript engine is just going to look up the prototype chain.
As a side note, whenever we get undefined on something for example,
Whenever the Javascript engine doesn't find anything up the prototype chain, we get these errors or undefined.
We see that if we go higher up passed this base object, we get null — Null meaning there is nothing there. When Javascript was created, Undefined was used for we don't have that variable.
Null meant there is absolutely nothing there.
Because of its prototypal inheritance nature, we needed a way to say, hey past the base object there is nothing there. That's why we have null.
Let's dig a little deeper.
But if I do obj.hasOwnProperty, I get an error because obj doesn’t have this method itself. It has this as a property up the prototype chain.
How about a function?
This is because a function is a special type of object. It's a callable object where we have code that can be invoked, we have an optional name field and we also have properties we can add to the function — this is all because its an object.
But these properties aren't on the multiplyBy5 function. Instead, this is up the prototype chain
With multiplyBy5 if I go up the prototype chain, I will have the native function that all functions get created from.
Now if we can capture this base function and store it, we see that all these properties come with this native function including apply(), bind() and call().
This is what's happening in diagram a:1:
multiply by 5 has a __proto__ property that links up to the native function that has call(), apply() and bind().
As you can see there is a pattern here: __proto__ links to prototype.
MultiplyBy5 — a callable object that is invokable, with name, properties(call, bind and apply) also has __proto__ that links to the native function which also has a prototype property. The prototype property is where call(), bind() and apply() live.
Let’s try this out.
__proto__ is simply a reference or a pointer to the object prototype up the chain.
__proto__ is simply a reference or a pointer to the object prototype up the chain.
Let's test this out further with an array.
Map property lives up the prototype chain with the base Array.
[].__proto__ is pointing to the father Array.prototype
To review,
Arrays and functions are objects in Javascript. multiplyBy5 is a special type of object that is a callable object. However it doesn’t have call, apply or bind as its own properties, it uses prototypal inheritance to inherit from the base function.
The key here is __proto__ points to the prototype up the chain and the __proto__ property actually lives on the prototype. This way we are able to be efficient with our memory, we are able to use the map function or for each. We just write them once instead of copying them each time.
How to create our own prototypes
We agreed that __proto__ isn’t something that we should use for performance reasons in our Javascript code.
There are many safe ways to do this.
Object.create is one of the ways we can use to inherit from an object in this case human
So that if we do:
Only functions have the prototype property
However, when we create a function like this, this prototype we don't really use. It just gets created but we never really make use of it. Now although prototype is a property on all functions, the only time that we really use it is when we create a constructor function.
Constructor functions usually start with a capital letter F and they contain the actual prototype or blueprint that we use.
For example, if I do:
Now we know that
Equals the same thing.
Now if we go up the chain again, we get our base object.
But we have just said that prototypes only exist on functions?
If I do Object.prototype, we get the same thing.
But haven’t we just said that the prototype property only exists on functions?
This is where things get a little confusing.
Because with this base object, if we do typeOf Object, we see that it’s a function!
Well, this is because it has the prototype property.
Remember the standard built-in objects in Javascript where we have all these things like Fundamental objects like Object, Function, Boolean, Number, and Dates, Strings — all with capital letters. If we open up the Object, we see that this object is the Object constructor that creates the object wrapper.
Remember that for us to perform an action in a program, we have to have a function — that's what a program does. It stores data, and we use functions to manipulate that data. So when we do something like const obj = {}, underneath the hood, Javascript has to create that object, and in order to create obj, it uses the object constructor.
Because this is now an actual object that we’ve created from the object constructor.
The takeaway?
Every function has a prototype property. And it references to an object used to attach properties that will be inherited by objects further down the prototype chain. The last object in a chain is the built-in object.prototype.
The takeaway?
Every function has a prototype property. And it references to an object used to attach properties that will be inherited by objects further down the prototype chain. The last object in a chain is the built-in object.prototype.
Remember the difference: Object is a function because it has the prototype. The Object.prototype is what we call the base object — that is the very last object that we can look for properties on before we point to null.
As a side note:
If I created an empty object, I wouldn't be able to access obj.prototype
It's undefined. It's not a function.
What about array.prototype?
Its also not a function.
And “string”.prototype?
It's also not available. We don't have prototype because well that's just a primary type.
Only functions have a prototype.
But from our standard built-in objects, if I do String.prototype, we have that.
And strings have all these methods from the String constructor that they can inherit from.
To summarise:
Everything in Javascript is an object. And arrays and functions in Javascript are objects. They inherit through the prototype chain from the base object.
You can go up the prototype chain looking for properties on the prototype property. The prototype property also has __proto__ inside of it that links higher up to the next prototype chain. __Proto__ always points to prototype.
And only functions have the prototype property.
At the end of the day, this was useful for us because using prototypes we avoid repeating ourselves. We avoid adding the same code over and over and being inefficient with our memory. But we can also start creating some interesting programing paradigms and practices using what we learned both prototypes and closures to write some really powerful programs.
Let's finish off with exercises.
Extend the functionality of the built-in Object.
1. Make the Date Object have a new method .last year() which shows you last year in YYYY format.
Solution
2. Modify .map() to print ‘ 🗺’ at the end of each item.
2. How would you be able to create your own .bind()
method using call
or apply?