There are many ways to do Object Oriented Programming in JavaScript. And there are multiple syntaxes for creating object inheritances. Given the fact that JavaScript is a functional prototype oriented programming language the classic inheritance pattern and syntax is not actually something which is on the top of the list for most JavaScript developers.
But what if your team or you are classical server side developer and are well versed in the Object Oriented Inheritance model found in Java, C# or PHP and you need to develop a JavaScript based RIA application?
Well there is a JavaScript inheritance model which is simple and is similar to the classic inheritance syntax used by more server oriented programming languages. Of course in JavaScript we don’ have private or protected methods but there are ways to handle that. What is important is the ability to create a proper inheritance tree in a very simple manner.
The basic inheritance story looks like this:
1: function User(){
2:
3: }
4:
5: User.prototype.Authenticate = function (username, password) {
6: return true;
7: }
8:
9: function Clerk(){
10: User.call(this);
11: }
12:
13: Clerk.prototype = new User();
14: Clerk.prototype.constructor = Clerk;
The class User is a basic class with a single method Authenticate. The method Authenticate doesn’t do much. The class Clerk inherits from the class User. The basic inheritance pattern is this:
1: Clerk.prototype = new User();
2: Clerk.prototype.constructor = Clerk;
The prototype of the class Clerk receives a new instance of the class User. The constructor of the class Clerk is reset again (since it was overridden in the previous call with the class User) to Clerk again.
Thus the class Clerk has now all the properties and methods of the class User. In the constructor of the class Clerk we call its parent constructor to initialize any constructor initialized properties or activities.
1: function Clerk(){
2: User.call(this);
3: }
The first parameter of the call function set the context of the this variable in the called function. With this line now the this in the User constructor is no longer the User class but the Clerk class.
The above example is the bare minimum you need to use in order to have classical inheritance in JavaScript. The next example will deal with three advanced concepts:
- Method overriding
- Passing parameters to the base constructor class
- Calling parent methods in overridden methods while conserving the this context
1: function Institute(name){
2: this._name = name;
3: }
4:
5: Institute.prototype.getName = function() {return this._name;}
6: Institute.prototype.setName = function(name) {this._name = name;}
7: Institute.prototype.educatePeople = function(){
8: console.log("The instititute " + this._name + " will educate 200 people this year");
9: }
10:
11:
12: function PrivateInstitute(name){
13: Institute.call(this,name);
14: }
15:
16: PrivateInstitute.prototype = new Institute();
17: PrivateInstitute.prototype.constructor = PrivateInstitute;
18:
19: PrivateInstitute.prototype.educatePeople = function(){
20: Institute.prototype.educatePeople.call(this);
21: console.log("And we will earn mucho dinero!";
22: }
In the above example we have two classes the Institute base class and the PrivateInstitute child class. The Institute class receives one parameter in its constructor its name.
When inheriting the Institute class the name parameter is passed to the parent constructor after the this parameter in the call method like this:
1: function PrivateInstitute(name){
2: Institute.call(this,name);
3: }
Both classes the implement the educatePeople method. The version in the PrivateInstitute class is a simple override. In order to override methods in JavaScript we just need to repeat their names and the that version will be used instead of the parent method. But what is we need to call the parent method, or a method belonging to a different ancestor in the inheritance tree? Well the syntax for that is a little different. We need to call the method on the prototype of the class of the ancestor we are calling the method on and as the first parameter we need to pass the current object instance like this:
1: PrivateInstitute.prototype.educatePeople = function(){
2: Institute.prototype.educatePeople.call(this);
3: console.log("And we will earn mucho dinero!";
4: }
Normally as was the case in the previous constructor example if the ancestor method receives any parameters they are passed after the this reference in the call method.
There is one further things one needs to be very carefull and is the this context in DOM event callbacks which reference to the DOM element being operated on. The following trick makes all the this pain go away.
1: SomeClass.prototype.callbackMethod = function(event) {
2: console.log(this.SomeProperty); //printing property belonging to the same class
3: Parent.prototype.SomeMethod.call(this);
4: }
5:
6: SomeClass.prototype.UIHandler = function(){
7: var self = this ; //alternate name for this
8: $('button').click(function(event) {
9: self.callbackMethod(event);
10: });
11: }
The main focus is the replacement of the this variable with the self variable in the scope of the method. The self variable in the callback of the click event handler is the SameClass this context thanks to the closure feature of JavaScript.
No comments:
Post a Comment