In the second article of the series of "Exploring OOPS - JavaScript Style", we look at how inheritance is implemented in JavaScript.
Note: This article is an adaption (may be a mirror) of the article originally posted at Edujini⢠Eduzine⢠here.
All the three articles of the series:
Inheritance can be described as reusability by virtue of heritage. An inherited data-type automatically obtains the functionality defined in the data-types from which it inherits.
JavaScript supports single inheritance, i.e., you can inherit from maximum one type. Also, it does not support the concept of interface introduced in languages like Java, C# to support multiple inheritance. In JavaScript what we have is instance-inheritance (or runtime inheritance) rather than class-inheritance (or compile-time inheritance) making inheritance more powerful than probably any other language around (barring the ones like Smalltalk)!
The downloads are available in the Downloads area.
In Part 1, we defined UserProfile with username and password. In this article, we create EmployeeProfile that inherits from UserProfile and adds employeeID. It also reimplements (override, if you like to use that word) authenticate method.
EmployeeProfile Definition
We start with defining EmployeeProfile with employeeID besides earlier properties. Create a file EmployeeProfile.js with the following code:
/** * Part of the Eduzine (http://eduzine.edujini-labs.com) Articles. * * Downloads available at http://downloads.edujini-labs.com * * (C) 2008, Edujini Labs Pvt Ltd * http://www.edujini-labs.com */ function EmployeeProfile(username, password, employeeID) { this.username = username; this.password = password; this.employeeID = employeeID; }
The next step is to mark it inherited from UserProfile. For this, we need to work with the property prototype that is always available to us whenever we declare a function. (Note that all functions can be used as constructor.) Add the following additional code at the end of the code above:
EmployeeProfile.prototype = new UserProfile();
Note the following:
UserProfile but through its instance.UserProfile has been created without passing any parameters to the method.
So, it's time to test the definition so far... Let's create EmployeeProfile.html with the following content:
<html> <head> <title>OOPS in JavaScript- Encapsulation</code> <script language="'javascript'" type='text/javascript' src='UserProfile.js'></script> <script language="'javascript'" type='text/javascript' src='EmployeeProfile.js'></script> <script language="'javascript'" type='text/javascript'> /** * Part of the Eduzine (http://eduzine.edujini-labs.com) Articles. * * Downloads available at http://downloads.edujini-labs.com * * (C) 2008, Edujini Labs Pvt Ltd * http://www.edujini-labs.com */ function validateUser() { var eid = document.getElementById('i').value; var uname = document.getElementById('u').value; var pwd = document.getElementById('p').value; var e = document.getElementById('result'); var ep = new EmployeeProfile(uname, pwd, eid); e.innerHTML = 'Username: ' + ep.username + '<br/>Password: ' + ep.password + '<br/>EmployeeID: ' + ep.employeeID + '<br/>Authenticate: ' + ep.authenticate(); } </script> </head> <body> Employee ID: <input type='text' name='i' id='i' /> <br/> Username: <input type='text' name='u' id='u' /> <br/> Password: <input type='password' name='p' id='p' /> <br/> <button onclick='validateUser(); return false;'>Login</button> <div id='result'></div> </body> </html>
I think the code is self explanatory. What we get is not only the three properties but also automatic definition of authenticate method for EmployeeProfile. After all, that's that inheritance is all about. In the definition of EmployeeProfile, we never mention about it but it is automatically available to it through its parent object UserProfile.
instanceof Operator
We'll explore method overriding and other complex (unexplored, not mentioned so far) things in a while. We take a short while to look at instanceof operator.
It is a binary operator. The left operand is the object-reference and the right operand is the function-definition (data-type reference). The operator returns a boolean value indicating whether the object is an instance of the corresponding type or not.
if(ep instanceof UserProfile) { alert('ep is an instance of type UserProfile'); } else { alert('ep is NOT an instance of type UserProfile'); }
You can add this code to the method validateUser. In our case, it must return true. Similarly, obj instanceof Object for any non-null value for obj will return true.
And a very crutial item before we get back on to our main agenda.
Depending upon how we write the code, the methods may be loaded in memory multiple times. Which is bad for the appliation. We do not want identical piece of code to be loaded in memory multiple times. The code must be loaded only once and be executed in the context of the corresponding object. What am I talking? Update the code for the method validateUser to as follows:
function validateUser()
{
var eid = document.getElementById('i').value;
var uname = document.getElementById('u').value;
var pwd = document.getElementById('p').value;
var ep1 = new EmployeeProfile(uname, pwd, eid);
var ep2 = new EmployeeProfile(uname, pwd, eid);
alert('Are references same? ' + (ep1.authenticate == ep2.authenticate));
}
You are bound to get a false! It hurts. :(
Everytime we instantiate EmployeeProfile (or even UserProfile for that matter), code for the method authenticate is loaded into memory. Imagine if we have 1000 instances. Not only the properties are loaded into memory 1000 times, but also the code for the method. It's just too bad.
Let's fix this up...
Update the code for UserProfile to as follows:
function UserProfile(username, password)
{
this.username = username;
this.password = password;
}
UserProfile.prototype.authenticate = function()
{
if(this.username == 'gvaish' && this.password == 'edujini')
{
return true;
}
return false;
}
Notice the use of prototype property once again. That holds the key! That's probably - The Key property in JavaScript.
Now, execute the test case once again. ep1.authenticate == ep1.authenticate must return true in this case! Detailed discussion around prototype is out of the scope of this article... but will have one some time soon.
Next, we explore how to override the method authenticate. Update the definition of EmployeeProfile to as given below:
function EmployeeProfile(username, password, employeeID)
{
this.username = username;
this.password = password;
this.employeeID = employeeID;
}
EmployeeProfile.prototype = new UserProfile();
EmployeeProfile.prototype.authenticate = function()
{
if(this.employeeID == 123 && this.username == 'gvaish'
&& this.password == 'edujini')
{
return true;
}
return false;
}
Go ahead and authenticate with various compbinations of the employeeID, username and password. Hurray! The method has been overridden (using the line of hierarchy of the object prototype).
The last thing that we see in method overriding is how to invoke the base-type method in the sub-type method. Well, the solution again lies in prototype!
Let us define the business logic for an employee's authentication as follows:
UserProfile. If it has failed, the result is failure.employeeID.
This way we keep EmployeeProfile independent of how the UserProfile authenticates itself. Modify EmployeeProfile to as follows:
function EmployeeProfile(username, password, employeeID)
{
this.username = username;
this.password = password;
this.employeeID = employeeID;
}
EmployeeProfile.prototype = new UserProfile();
EmployeeProfile.prototype._authenticate = EmployeeProfile.prototype.authenticate;
EmployeeProfile.prototype.authenticate = function()
{
if(this._authenticate())
{
return this.employeeID == 123;
}
return false;
}
Note that this is one of the various possible ways of achieving our target. We create a reference _authenticate to the original authenticate method (but did we get it from EmployeeProfile since we defined it in UserProfile - that's the magic of prototype in JavaScript).
Rerun your test case... Wow! We get what we expect...
In this article we learnt how encapsulation is implemented in JavaScript. To summarize, we explored the following:
prototype property to mark inheritance.instanceof operator to check the underlying data-type inheritance hierarchy.| You must Sign In to use this message board. | ||||||
|
||||||