In this section, we will learn what the Prototype is and how to use it in JavaScript.
What is Prototype in JavaScript? Function Prototype in JavaScript
Functions are a sub-type of objects. This means we can add a property to them and invoke that property at later times.
For example:
function boo(){ //body... } boo.fullName = "John Doe"; console.log(boo.fullName);
Output:
John Doe
The `boo()` is a function in this example but as you can see, we used the `boo.fullName = “John Doe”;` statement to add a property to this function and assigned a value to that property as well.
So in the statement:
console.log(boo.fullName);
When we used the `boo` function to get the `fullName` property, the execution engine checked the list of properties of this function and saw the property. So it sent its value to the browser’s console.
You should know that any function in the JavaScript has one property named `prototype`. The value of this property is an object. So basically, the `prototype` property represents an object.
Inside that object there’s a property named `constructor` that has the memory address of the related function as its value (related function is the function that this prototype object belongs to).
Example:
function boo(){ //body... }
Here, the function `boo` has the `prototype` property automatically added to it.
So just to make it clear, there’s no difference between calling the `boo` function like `boo()` and `boo.prototype.constructor()`. Both result in invoking the body of the same function.
We will explain this part in just a moment, but for now just remember the object that the `prototype` is referring to is linked to another object as well.
Now let’s start from the origin to understand this linked relation (AKA inheritance).
JavaScript Object.prototype
Before the execution of the first line in our program, JavaScript automatically adds one function named `Object` to our program.
Since the `Object` is a function, it has the hidden property named `prototype`.
This property, of course, is linked to an object and inside that object there are multiple properties, including the one that is called `constructor`.
JavaScript Prototype Constructor
Starting from the top level, we mentioned that object function has a property named `prototype` and this prototype represents an object.
Inside this object there are multiple properties and one of them is called `constructor`.
The `constructor` property has the memory address of the `Object` function.
So invoking the `constructor` property like `Object.prototype.constructor()` is the same as if we’ve invoked the `Object` function itself like `Object()`.
Example: using constructor property of the prototype object
const obj = new Object.prototype.constructor(); const obj2 = new Object();
Here both `obj` and the `obj2` are created from the `Object` constructor even though we’ve used the `constructor` property for the `obj`. Again, this is because the `constructor` property refers to the same function body.
Note: besides the `constructor` property, the prototype-object of the `Object` function has other properties as well, but in this section we don’t need to learn them. We’ve explained them in the Object Constructor section.
Prototype Inheritance in JavaScript
So far we know that there’s a constructor function in every program called `Object`. This constructor function has a property named `prototype` which is an object with multiple properties (one of them is named `constructor`).
We also know that each function that we create in JavaScript has a property named `prototype` and that is also an object which has only one property named `constructor`.
The next thing we should know is that, by default, the prototype object of each function is linked to the prototype of the `Object` constructor function.
We will get into this “link” part in just a moment.
You should know that objects that we create are also linked to a prototype object, but:
- If the target object is a literal object, then it is linked directly to the prototype object of the constructor function `Object`.
- If the target object is created using a function constructor, then the object is linked to the prototype object of the function constructor that the object is created from. And of course because the prototype object of each function is linked to the prototype object of the `Object` function, then we can say these types of objects are also indirectly linked to the prototype object of the `Object` constructor function at the end.
The diagram above shows how each function and object in a program finally is linked to the prototype object of the `Object` constructor function.
So now the question is: what does this link do, actually?
When we invoke a property of an object:
- First, the execution engine will look into the body of that object to see if there’s property with such name. If it found one, it will invoke the value of that property.
- If the execution engine could not find such property name in the target object, it will use the `link` and moves to the prototype object of the function that this object is created from (in case the object was created using a constructor function). The execution engine will look into that prototype object to see if the target property is declared in there.
- If the engine could not find the property in the prototype object as well, it will again use the link to go one level higher. As mentioned at the beginning of this section, the prototype object of all functions that we create in a program is linked to the prototype object of the `Object` function at the end. So the execution engine will check the body of that object as well and finally if it couldn’t find the target property, we will get a reference error.
This is called inheritance in JavaScript.
Note: inheritance is a concept that was created in the world of Object-oriented programming languages like Java and C# etc. but what you saw here is not specifically inheritance! Though because the concept of inheritance is a known model and people usually can relate to it more easily, the term “inheritance” is also used in JavaScript.
But you should remember that the reality in JavaScript is that there are just links between objects and functions! There’s no such thing as inheritance in JavaScript.
As long as you stick to this linking model, you’ll face no trouble at all.
Example: using prototype to implement inheritance in JavaScript
function Person(){ } Person.prototype.firstName = "John"; Person.prototype.lastName = "Doe"; let prs = new Person(); console.log(prs.firstName); console.log(prs.lastName);
Output:
John Doe
JavaScript Prototype Chain
The constructor function, `Person` is an empty function. So essentially creating an object from this function will result in an empty object.
But in the prototype of this function we’ve added two properties named `firstName` and `lastName` via the two statements below:
Person.prototype.firstName = "John"; Person.prototype.lastName = "Doe";
So besides the `constructor` property, the prototype object of the `Person` now has these two properties as well.
After that, we create a new object via this constructor function and stored that in the `prs` variable.
As mentioned before, an object that is created from a function has a hidden link to the prototype object of that function.
This means the object that we’ve created and stored in the `prs` variable has this link to the prototype object of the `Person` function.
Now let’s see what will happen when we call the `prs.firstName` in the statement:
console.log(prs.firstName);
- The execution engine will first check the body of the `prs` object to see if there’s a property with the name `firstName`.
- Because there’s no property with this name, the execution engine will use the link connection and move to the prototype object of the `Person` function to see if in that object there’s a property with the name `firstName`.
- Because there’s a property with this name, its value will be used as the replacement in the call `console.log(prs.firstName);`.
- After that, the value `John` will be sent to the browser’s console.
The next statement is `prs.lastName` in the:
console.log(prs.lastName);
This statement is also treated the same way. This means the execution engine will look into the `prs` object and searches for a property named `lastName`. But because there’s no property here, it will look into the prototype object of the `Person` function. In that object, because this property is declared, it will use its value and send the result to the browser’s console.
Note: if the prototype object of the `Person` function also didn’t have such property, the execution engine uses the link between the Person’s prototype object and the prototype object of the `Object` function to look into that object as well. At the end, if the property wasn’t there too, we would get a reference error.
Also, if we create an object literal, it will be directly linked to the prototype object of the `Object` function.
So basically an object literal has the access to the properties of the prototype object of the `Object` function and can use those properties if it didn’t override them.
You should remember that the search of the execution engine starts from the object itself. If the object itself didn’t have the target property, in that case the engine will use the link to search the next prototype object and so on.
Example: function prototype in JavaScript
function Person(){ } Person.prototype.firstName = "John"; Person.prototype.lastName = "Doe"; const prs = new Person(); prs.firstName = "Omid"; console.log(prs.firstName); console.log(prs.lastName);
Output:
Omid Doe
Here the `prs` object has one property, and that is `firstName`. Also, the prototype object of the `Person` function has the same property.
Now when we ran the statement `console.log(prs.firstName)`, because the `prs` object already has such property, the execution engine will use the value of this property instead of going into the prototype object of the `Person` function.
JavaScript Function Prototype Object is shared
Alright, just to be clear, the prototype object of a function is shared between all the objects that are created from that function.
This means if one object changes the property value of a shared prototype, object; the other objects can see that change as well.
Example: using __proto__ in JavaScript
function Person(){ } Person.prototype.firstName = "John"; Person.prototype.lastName = "Doe"; let prs = new Person(); let prs2 = new Person(); prs.__proto__.firstName = "Omid"; console.log(prs2.firstName);
Output:
Omid
What is __proto__ in JavaScript?
First of all, in order to access the properties of a prototype object via the object that is created from that function, we use the dunder proto.
The dunder proto is written like this: __proto__ (two underscores on the left and two underscores on the right side of the word `proto`).
In this example, we used the `prs` object to access the prototype object of the `Person` function via the duner proto. After that, we’ve changed the value of the `firstName` property to `Omid`.
This is the statement:
prs.__proto__.firstName = "Omid";
Now when we use the `prs2` to get the value of the `firstName` property, we got the value `Omid` instead of the previous value, which was `John`.
Notes:
- If we wanted to access the prototype object of the `Object` function, we needed to use the dunder proto two times.
For example:
prs.__proto__.__proto__.propertyName;
Basically, each call to the dunder proto will move one level up the chain.
- If we didn’t use the dunder proto, the execution engine creates the `firstName` property for the `prs` object itself because this object didn’t have such property in its body.
- Basically, when we call a property to get its value, the object and all its prototype objects in the chain will be searched to find the value.
- But if the property was called to assign a value to it and the target object didn’t have such property, the engine will create a new property in the target object instead of searching the chain for that property.