We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.
One of the key features of JavaScript language is its support for prototype method. This feature could be used to bring inheritance in JavaScript.
1function Person(dob) {
2 this.dob = dob;
3 this.votingAge = 21;
4}
1function Developer(dob, skills) {
2 this.dob = dob;
3 this.skills = skills || "";
4 this.votingAge = 21;
5}
1// create a Person instance
2var person = new Person("02/02/1970");
3
4//create a Developer instance
5var developer = new Developer("02/02/1970", "JavaScript");
As you can see both Person and Developer objects have votingAge property. This is code duplication. This is an ideal case where inheritance can be used.
Whenever you create a function, that function instantly gets a property called prototype. The initial value of this prototype property is empty JavaScript object {}
.
1var fn = function () {};
2fn.prototype; //=> {}
JavaScript engine while looking up for a method in a function first searches for method in the function itself. Then the engine looks for that method in that functions' prototype object.
Since prototype itself is a JavaScript object, more methods could be added to this JavaScript object.
1var fn = function () {};
2fn.prototype.author_name = "John";
3var f = new fn();
4f.author_name; //=> John
Currently Person function is defined like this.
1function Person(dob) {
2 this.dob = dob;
3 this.votingAge = 21;
4}
Problem with above code is that every time a new instance of Person is created, two new properties are created and they take up memory. If a million objects are created then all instances will have a property called votingAge
even though the value of votingAge is going to be same. All the million person instances can refer to same votingAge method if that method is define in prototype. This will save a lot of memory.
1function Person(dob) {
2 this.dob = dob;
3}
4Person.prototype.votingAge = 21;
The modified solutions will save memory if a lot of objects are created. However notice that now it will a bit longer for JavaScript engine to look for votingAge
method. Previously JavaScript engine would have looked for property named votingAge
inside the person object and would have found it. Now the engine will not find votingAge
property inside the person object. Then engine will look for person.prototype and will search for votingAge
property there. It means, in the modified code engine will find votingAge
method in the second hop instead of first hop.
Currently Person is defined like this.
1function Person(dob) {
2 this.dob = dob;
3}
4Person.prototype.votingAge = 21;
If Developer Object wants to extend Person then all that needs to be done is this.
1function Developer(dob, skills) {
2 this.skills = skills || "";
3 this.dob = dob;
4}
5Developer.prototype = new Person();
Now Developer instance will have access to votingAge
method. This is much better. Now there is no code duplication between Developer and Person.
However notice that looking for votingAge
method from a Developer instance will take an extra hop.
Since only the methods that are common to both Developer and Person are present in the Person.prototype there is nothing to be gained by looking for methods in the Person instance. Next implementation will be removing the middle man.
Here is the revised implementation of Developer function.
1function Developer(dob, skills) {
2 this.skills = skills || "";
3 this.dob = dob;
4}
5Developer.prototype = Person.prototype;
In the above case Developer.prototype directly refers to Person.prototype. This will reduce the number of hops needed to get to method votingAge
by one compared to previous case.
However there is a problem. If Developer changes the common property then instances of person will see the change. Here is an example.
1Developer.prototype.votingAge = 18;
2var developer = new Developer("02/02/1970", "JavaScript");
3developer.votingAge; //=> 18
4
5var person = new Person();
6person.votingAge; //=> 18. Notice that votingAge for Person has changed from 21 to 18
In order to solve this problem Developer.prototype should point to an empty object. And that empty object should refer to Person.prototype .
Here is revised implementation for Developer object.
1function Developer(dob, skills) {
2 this.dob = dob;
3 this.skills = skills;
4}
5var F = function () {};
6F.prototype = Person.prototype;
7Developer.prototype = new F();
Let's test this code.
1Developer.prototype.votingAge = 18;
2var developer = new Developer("02/02/1970", "JavaScript");
3developer.votingAge; //=> 18
4
5var person = new Person();
6person.votingAge; //=> 21
As you can see with the introduction of empty object, Developer instance have votingAge of 18 while Person instance have votingAge of 21.
If child wants to access super object then that should be allowed. That can be accomplished like this.
1function Person(dob) {
2 this.dob = dob;
3}
4Person.prototype.votingAge = 21;
5
6function Developer(dob, skills) {
7 this.dob = dob;
8 this.skills = skills;
9}
10var F = function () {};
11F.prototype = Person.prototype;
12Developer.prototype = new F();
13Developer.prototype.__super = Person.prototype;
14Developer.prototype.votingAge = 18;
The whole thing can be captured in a helper method that would make it simple to create inheritance.
1var extend = function (parent, child) {
2 var F = function () {};
3 F.prototype = parent.prototype;
4 child.prototype = new F();
5 child.prototype.__super = parent.prototype;
6};
A simpler form of pure prototypal inheritance can be structured like this.
1if (typeof Object.create !== "function") {
2 Object.create = function (o) {
3 function F() {}
4 F.prototype = o;
5 return new F();
6 };
7}
Before adding the create method to object, I checked if this method already exists or not. That is important because Object.create
is part of ECMAScript 5 and slowly more and more browsers will start adding that method natively to JavaScript.
You can see that Object.create takes only one parameter. This method does not necessarily create a parent child relationship . But it can be a very good tool in converting an object literal to a function.