Prototypal Inheritance in JavaScript
There is a great article written by Douglas Crockford. I recommend everybody to read this article. By using Prototypal inheritance technique, we can create the instance of an object. Suppose, we have one object User, we want to create the instance of the user object and use it in different-2 places. In order to create the instance of an object, we can set the prototype property of an Constructor Function equal to the object and then we can instantiate that constructor function to create the instance of that object. Below is the create method that will help us to do so. This method is taken from Doug's article.
/* creating a method that will pops up the new objects inherited with the old object. */ if ( Object.create !== "function") { Object.create = function (oldObj) { function F () {} ; F.prototype = oldObj; return new F (); } }
Now let's say we have one object User that has one property say name that is an array. It has name array property and `addName` method to add new name in the array.
Explaining Prototype Example
/* User is a simple object contains 3 methods and one property */ var User = { name : [], addName:function(n) { this.name.push(n); }, getName : function ( ) { alert(this.name); } };
Now, by using `Object.create` method, we can create instances of the User object.
/* creating one instance of User */ var user1 = Object.create(User); user1.addName("Rupesh"); user1.getName( ); // Wo return "Rupesh"
/* creating another instance of the User */ var user2 = Object.create(User); user2.addName("Ritesh"); user2.getName( ); // Will return "Rupesh", "Ritesh"
We saw that how easily we can create the instances of an object and can use its properties and methods using Prototypal inheritance.
I like Prototypal inheritance because it has many advantages one of them is it saves memory. Because, when we create new object by putting old object in its prototype property then we don't refer to the concrete old object rather we refer to the property of an object which has a link or which refer to or which points to the concrete old object. It also help us to create the loosely coupled architecture.
However, in above User object there is one problem!! The problem is when you call `user1.getName( )` it will alert Rupesh. When you call `user2.getName( )` it will alert Rupesh, Ritesh. This is a problem!! This was never expected. We thought that we are creating two different new instances user1 and user2. Which will have their own name properties and will store different values. But it is not the case!!!
Let's analyze the Prototype Chain
When we write the code user1.addName("Rupesh"); The user1, new object will look for the name property in user1 object. It will not find the name property in the user1 object. So, it will go to the prototype object which is a User object and there it will search for the name property and finally it updates the name property of the prototype object which is nothing but the User Object. Therefore, the next time when user2.addName("Ritesh") is called, it again looks for name property in this (user2) and it again fails to find the name property in user2 object. Therefore, it searches in user2's prototype object for name property. There exists User object that has name property and user1 has already entered "Rupesh" in this property so user2 again enters "Ritesh" in the same name property and hence when we do user2.getName( ) then it says "Rupesh, Ritesh".
Whatever data is entered by the user1 in name property. It is inserted in the prototype objects name property that is also shared with user2. That means, they are sharing the same name property. It's like a static property that is being used by the multiple instances of the User object. But, that was not intended. We wanted a new fresh object in each instance.
In order to achieve that, we can introduce one method to User object say init. In this method we will initialized the name property with a new array and assign it to the instance object "this".
var User = { init:function ( ) { /* we are initializing its name property in new instance or new object. */ this.name = []; }, name :[], addName:function(n) { this.name.push(n); }, getName : function ( ) { return this.name; } };
Now if we write below code to set and get the name property then each instance will have different or their own values.
// creating one instance of User var user1 = Object.create(User); //calling its init method user1.init( ); /_ Here we are adding to the same name property of the new instance of the User object. _/ user1.addName("Rupesh"); user1.getName( ); // Result = Rupesh //creating another instance of the User var user2 = Object.create(User); user2.init( ); user2.addName("Ritesh"); user2.getName( ); // Result = Ritesh
Now the `user1.getName()` will return Rupesh and `user2.getName()` will return Ritesh. Because, now obj1 and obj2 will have common shared methods but they will have their own distinct name properties.
Conclusion
I think, I was able to explain the prototypal inheritance clearly. If you have any suggestions then plz put your comments, I want to learn more from you.
Related Articles
- Javascript Jems - a new take on objects (i-programmer.info)
- Class - digg - Class creation and management for jQuery - Project Hosting on Google Code (code.google.com)
- CLiki : ParenscriptClassicOO (cliki.net)
- (really) understanding javascript prototypes (javascriptweblog.wordpress.com)
- Javascript Jems - Object factories, constructors and clones (i-programmer.info)
- Determining if an object property exists (nczonline.net)
- Book Review: Object-Oriented JavaScript (elegantcode.com)
- Classes in JScript - Part III: Class Hierarchy and Data Encapsulation (blogs.msdn.com)
- Advantages of prototype based OO over class based - Stack Overflow (stackoverflow.com)
Comments