JavaScript Prototype and Prototype Chain explained.
In this article, I’m trying to explain some of the core concepts
in the JavaScript related to the Prototype and Prototype Chain.
Before deep dive into those concepts let’s see what is the
requirement of having Prototypes in JavaScript.
Why we need Prototype
Let’s look at the following example where you need to create a
person object in your JavaScript program.
let person = {};
person.name = 'Leo';
person.age = 20;person.eat = function () {
console.log(`${this.name} is eating.`)
}person.sleep = function () {
console.log(`${this.name} is sleeping.`)
Then think of a scenario where you might need more than one person
in your program, what would you do in that case? You would create
a separate function which will generate a Person object for you.
Isn’t it?
Something like this??
function Person(name, age) {
let person = {};
person.name = name;
person.age = age; person.eat = function () {
console.log(`${this.name} is eating.`)
} person.sleep = function () {
console.log(`${this.name} is sleeping.`)
} return person;
}// Invoke Person function to create persons.
const person1 = Person('Mike', 23);
const person2 = Person('Alis', 34);
That is great right? But is this the correct way to do
that?
No, Think of another scenario where you building a more complex
application and there you would need millions of such Person
objects, in that case at each time we create a Person object it
will recreate eat and sleep methods in the memory. Which eats your
memory.
Instead of doing something like above, what if we can create those
methods once and reuse them as references inside the Person
function. In that way, we will create those methods only once in
the memory. See the example below.
const PersonMethods = {
eat = function () {
console.log(`${this.name} is eating.`)
},
sleep = function () {
console.log(`${this.name} is sleeping.`)
}function Person(name, age) {
let person = {};
person.name = name;
person.age = age;
person.eat = PersonMethods.eat;
person.sleep = PersonMethods.sleep; return person;
According to the above example, we have created a Person methods
object once in the memory and at each time when we are creating a
new Person, we are giving them the reference to that PersonMethods
object’s methods. That way we have resolved the memory issue we
had.
Wow, that is great right? Are we done?
No, Again this method also has some drawbacks. Can you guess?
Were you able to guess the issue with this code? If not don’t
worry let me explain the downside of this code. Let’s assume that
later we decided to add a new method to the Person, what would you
do? Then we have to add that method to the PersonMethods and then
we have to modify the Person function to reference that newly
introduced method as follows.
const PersonMethods = {
eat = function () {
console.log(`${this.name} is eating.`)
},
sleep = function () {
console.log(`${this.name} is sleeping.`)
},
walk = function () {
console.log(`${this.name} is walking.`)
},
}function Person(name, age) {
let person = {};
person.name = name;
person.age = age;
person.eat = PersonMethods.eat;
person.sleep = PersonMethods.sleep;
person.walk = PersonMethods.walk; return person;
Hmm, that is not a major issue, but isn’t it great to have a
common place where we can do changes like above and reflect those
changes on all the created instances? Without having to modify all
the created instances. Instead of doing something like above. That
is where the Prototype comes into the picture in the JavaScript.
Prototype
Prototype is basically a property of a JavaScript function. At
each time we create a function in JavaScript, JavaScript engine
adds an extra property called prototype to the created function.
This prototype property is an object (called as prototype object)
has a constructor property by default. This constructorproperty
points back(i.e blue arrow) to the function object on which
the prototype object is a property. Following diagram illustrates
what I described above.
prototype property points to the Prototype object of the
function(i.e green arrow). We can access the function’s prototype
property using the syntax functionName.prototype. and from the
Prototype object of a function, we can again access the function
object back by functionName.prototype.constructor. If you are
still confused let’s write few codes to understand this.
Creating objects using constructor functions
Hope now you have a slight idea about what prototype is, before
dig into more on this topic let’s first understand one small
concept in JavaScript. That is constructor functions. Please read
my article on Constructor functions in order to have a solid idea
about what is a constructor function and what it does.
Now, Let’s write a construction function which
accepts name and age as function parameters as follows and logs
out its prototype object:
function Person(name, age) {
this.name = name;
this.age = age;
console.log(Person.prototype)
You will see a console output as follows :
As you can see in the above when we console
log Person.prototype it has logged out the created function’s
prototype object. And there we can see two
attributes constructor and __proto__ properties. (For the moment
forget about this __proto__ property in the function’s prototype
object. ) Then let’s logs out the Person.prototype.construcor
See, it looks like the function we defined a few second ago. As I
described above when we create a function, it creates another
object called prototype object which has a constructor property
which points back to the function object and the function itself
has a property called prototype which points to the function’s
prototype object. Let’s see whether those points are correct. If
those statements are correct then the identity operator (===) in
JavaScript should be
evaluated true for Person.prototype.constructor ===
Person and Person.prototype ===
Person.prototype.constructor.prototype cases.
As we expected those gives true for the above cases. Which means
whatever the things I described above are correct. I hope now you
have a proper understanding of what is the prototype in
JavaScript.
Now let’s see how we can use above mentioned prototype object to
solve the issue we had earlier. Let’s see what happens if we put
all our custom functions into the prototype object instead of
creating a separate object for those and assign them inside the
function definition as follows :
function Person(name, age) {
this.name = name;
this.age = age;
}Person.prototype.eat = function () {
console.log(`${this.name} is eating.`)
}Person.prototype.sleep = function () {
console.log(`${this.name} is sleeping.`)
}Person.prototype.walk =function () {
console.log(`${this.name} is walking.`)
Then let’s create a new Person called Bob and logs out the Bob as
follows :
Ohh no!!, there are no methods available under the
names eat, age and walk. Isn’t it?
Well, that is not the case, remember what we learned earlier and
what we did? We added those methods to the function’s prototype
object. And as you can see there is something interesting has
happened.
There is another property in the Person instance Bob (i.e
__proto__), but we did not add that property to the object we
created right? So what is it? Basically, this __property__ is
the getterand setter to the function's prototype object. Okay I
know this sounds confusing, let me explain this in simple terms.
Let’s look at what we did to our constructor function :
• First, we defined our constructor function Person.
• Then we added methods to its prototype object.
When we add functions or properties (you also can add
properties) to the any function’s prototype object it will
be available to its instances through the prototype
object.
Then let’s look at what happened when we creating the instance
from the Person constructor function.
• We created an object called Bob with two attributes using the
Person function with the new keyword.
• Then behind the scene from the JavaScript engine, it adds a new
property called __proto__ to that instance which is a
getter/setter for the above Function’s prototype object.
• (Hope you read my article on Constructor Functions in
JavaScript if you are not familiar with JavaScript constructor
functions.)
That is what happened from the above code we wrote. And let me
illustrate those in a simple diagram which lets you understand
those very easily.
So basically if the __prototype__ property in the Bob is point to
the Prototype object of the Person constructor function object,
then it should have those methods we defined. To see that let’s
expand that __prototype__ property in the Bob.
If all the things we discussed are correct then prototype property
(__proto__) in the Person instance Bob pointing to the same object
of the Person construction function’s prototype object. We can
evaluate using the identity operator as we did before.
Yes, we were correct. Object instance prototype property (i.e
__proto__) and Function’s prototype property pointing to the same
object. Now let’s create another instance of Person and let’s see
whether that instance’s pointing to the same prototype object.
As we can see in the expanded console output, it looks like new
instance’s prototype property also pointing to the same object. If
that is true then identity operator evaluation for Alex.__proto__
=== Bob.__proto__ and Person.prototype === Bob.__proto__ should be
evaluated to true. Let’s see.
Yes, it is Alex’s prototype property (i.e __proto__)also pointing
to the same Object as the Alex prototype property (i.e __proto__).
Which gives a relationship as depicted in the following diagram.
So as a summary we can point out what we learned.
• When we create a function, JavaSctipt engine automatically
creates a Prototype object for that function and
add prototype property to Function object which can be used to
access that Prototype object, as well as it
adds constructor property which points back to the Function
object.
• Then when we create instances from the Function object, then
again JavaScript engine adds add getter/setter (i.e
__proto__) to object’s instance which can be used to access the
same prototype object of the Function object.
• This Prototype object of the constructor function is shared
among all the objects created using the constructor function.
We can add methods and properties into this prototype object
and then those automatically will be available to its
constructor function ’s instances.
NOTE: This __proto__ usually called it as dunder proto in
the JavaScript world.
Hope you have a solid understanding of what is known as Prototype
in JavaScript. Next will have a look at the Prototype chain.
Prototype Chain
By now you should have a solid understanding of what is
Prototype in JavaScript, next will try to understand what
is Prototype Chain. In order to understand that let’s do a small
exercise. Let’s create a simple object and then alert the object.
Alert output as follows:
Okay, how on earth we get this [object Object] from the alert as
an output? appleis an empty object and it does not have any
properties which hold such data or function which can generate
something like that. It seems like something has happened behind
the scene. Let’s dig this bit further. First, let’s console out
the apple and see whether we can find anything there.
Oh, there is nothing in it, but if we expand the apple object we
can see __proto__property in it. Okay cool, that’s interesting.
This gives us a hint that this is pointing to a some function’s
prototype object. Let’s console log that and see whether we can
find anything from that.
Ohh, There are lots of functions on it. But where this is coming
from? and Whose prototype object is this? And there is
a toString() function on it. To my sense, it feels like that
output we saw from alert might have generated from this method.
Let’s see.
Yes, it is!!!! Finally, we found out how we go that output from
the alert. That is when we alerting that apple object, the
JavaScript engine has called this toStringmethod in some object’s
prototype object’s function in order to generate this output. Then
we have another unresolved mystery. That is, whose prototype
object is this?
In JavaScript, there are set of built-in Objects such
as Object, Array, Date, Function etc and each of those objects
will have respective prototype objects attached to it.
In the above case, it was the Object construction function which
invoked to create the apple instance. That is because const apple
= {} is the same as const apple = new Object() where Object is the
built-in constructor function.
And that function has Object.prototype, which has all the methods
we saw earlier. If what we found out true then we can use the
identity operator (===) to evaluate the facts that we are familiar
with.
If Object constructor function was invoked when creating the apple
instance then Object.prototype and apple.__proto__ should point to
the same prototype object.
Yeah, we were correct. Those were pointing to the same prototype
object. And also following will also be obviously true if that
prototype object belongs to the Object constructor function
Object.
Let me draw a simple relationship diagram to show what we
discussed :
Also please note that unlike other function’s prototype object,
Object function constructor’s prototype object does not have
a __proto__ property inside it. If we console log its value, it
should be null.
To understand the reason for this; first, we need to have an
understanding of object lookup behavior in JavaScript. When we
look for a property of an object (including function
declarations), the JavaScript engine will first check the object
itself for the existence of that property.
If not found, it’ll go to the object’s prototype object and check
that object. If found, it’ll use that property. If that is not
found in that object then it will lookup on that prototype
object’s prototype object, If found it there, it’ll use that
property or else lookup continues until it finds an object with
a __proto__ property equal to null.
That is the JavaScript built-in object’s prototype object. Here it
has set to null in order to terminate the prototype lookup chain.
This is called the prototype chain. This is why we
see undefined for the values which are not defined in the any of
the prototype type chain objects.
Please Note [extracted from MDB Web Docs:
Following the ECMAScript standard, the
notation someObject.[[Prototype]]is used to designate the
prototype of someObject. Since ECMAScript 2015,
the [[Prototype]]is accessed using the
accessors Object.getPrototypeOf() and Object.setPrototypeO
f().
This is equivalent to the JavaScript
property __proto__which is non-standard but de-facto
implemented by many browsers.
It should not be confused with the func.prototype property
of functions, which instead specifies the [[Prototype]] to
be assigned to all instances of objects created by the
given function when used as a constructor.
The Object.prototype property represents
the Object prototype object.
Let me put all of these into a simple relationship diagram which
lets up to grasp this easily.
Also, other built-in Objects such as Array, Date, Function etc
also has an associated prototype and those have all additional
methods which are specific to that type.
For an instane, if we create a simple number array [1, 2, 3], the
default new Array() constructor function get invoked internally,
from the behind the scene by the JavaScript engine.
And also JavaScript will add a __proto__ pointer to newly created
array instance which points to the Array. prototype
(i.e Array.prototype) object which has all the methods relevant to
the Array operations such as concat, reduce, map, forEachetc.
And also if we log the newly created array instance prototype
object’s prototype (i.e numArray.__proto__.__proto__) we can see
that it has a pointer to another object, which should be
the Object.prototype.
Yes, it seems correct, as we did before let’s evaluate few
expressions with identity operator to check whether what we
learned is correct.
By specification, all built-in Objects in JavaScript has
prototype Object associated with it and it points to the
Object.prototype object. That is why many people
say “Everything in JavaScrtipt is inheriting from Object.”
There are few other things which I want to point out related to
the prototype chain in JavaScript, that is method override.
As we learned so far every object we create inherits its methods
and properties from its prototype objects chain. And also we
should know that we can override those methods as the way we want.
Let’s look at the following console output.
when we are logging out the number array that we created we can
see a nicely printed values array. How is this possible? That is
because Array.prototypeobject has a custom toString() method
implementation to do this.
So when we are console.log this array from the JavaScript engine,
behind the scene calls that method. But as we
learned Object.prototype object also has a toString()method.
But for the created numArray instance the closes method it fined
when looking up the toString( ) function along the prototype chain
it will be the Array.prototype object’s toString() method. Hence
engine will use that method to print out the elements in the array
to console output.
All the other built-in objects also work the same way. Such as
Functions, Date etc.
Prototype with Primitives
Next thing I want to highlight is the prototype
with Primitives. It is the most intricate thing happens when it
comes to the prototypes. As we know those are not objects in the
JavaScript, But when we try to access their properties JavaScript
engine will automatically create a temporary wrapper object
creates using built-in constructor function such as String,
Number, Boolean, Symbol(ES6)except for the null and undefined.
Those will provide additional methods to use with primitives.
Those objects created under the hood by the JavaScript engine and
will not be visible to us. Many JavaScript engines such as V8,
SpiderMonkey has their own optimizations to that as well.
Values null and undefined have no object wrappers. Those will
stand apart as special values in JavaScript when it comes to the
primitives.
Since they do not have object wrappers, simply they will not have
additional methods and properties for them and also they don’t
have any associated prototype object too.
So far we have learned quite a lot about
JavaScript Prototype and Prototype Chain , Now let’s put all of
our understandings into one big diagram to recap everything we
learned.
Hope I have covered everything related to the JavaScript Prototype
and Prototype Chain. If you have any questions related to these
concepts, feel free to ask anything in the comment section.
Cheers!!