Monday, August 30, 2010

Object Oriented JavaScript

How to write Object Oriented javascript ?
I explain simple steps to convert your plain javascript code to an object oriented javascript code.

1.) I will guide you to start with a simple function to the object oriented function at last.
2.) How to do multiple inheritance like in C++, Multi level inheritance like in Java
3.) Friend function like C++
4.) what do you mean by Redefinition in Javascript?
5.) How to design package ?
6.) how to use __proto__, instanceof ?
7.) Singleton design pattern
8.) Enum function
9.) what is prototype.constructor and when to use it ?

step-1: Look at this simple Function.

function add(a, b) {
return a + b;
}

function sub(a, b) {
return a – b;
}

var sum = add(2, 3);
var diff = sub(2, 3);

step-2: Another way by anonymous function

var add = function(a, b) {
return a + b;
}

var sub = function(a, b) {
return a – b;
}

var sum = add(2, 3);
var diff = sub(2, 3);

step-3: By anonymous function, executing it immediately

var sum = function(a, b) {
return a + b;
} (2, 3);

var diff = function(a, b) {
return a – b;
} (2, 3);

step-4: By Object level functions

var math = new Object();

math.add = function(a, b) {
return a + b;
}

math.sub = function(a, b) {
return a – b;
}

var sum = math.add(2, 3);
var diff = math.sub(2, 3);

//or

var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);

step-5: By Function Map

var math = {
“add” : function(a, b) {
return a + b;
},

“sub”: function(a, b) {
return a – b;
}
};

var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);
//or
var sum = math.add(2, 3);
var diff = math.sub(2, 3);

step-6: Now look at how to make it much more object oriented

function Math() {
this.add = function(a, b) {
return a + b;
};

this.sub = function(a, b) {
return a – b;
};
return this;
}

var math = new Math();

var sum = math.add(2, 3);
var diff = math.sub(2, 3);
//or
var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);

//drawback: You cannot redefine the member functions commonly

step-7: Now, i am introducing 'prototype', prototype is like a map which holds the the object member definition of any Function

function Math() {
return this;
}

Math.prototype.add = function(a, b) {
return a + b;
}

Math.prototype.sub = function(a, b) {
return a – b;
}

var math = new Math();
var sum = math.add(2, 3);
var diff = math.sub(2, 3);

//or

var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);

Note: ‘prototype’ is present inbuilt in all normal function

step-8: Another way of implementing it as like a map

function Math() {
return this;
}

Math.prototype = {
add: function(a, b) {
return a + b;
},

sub: function(a, b) {
return a – b;
}
};

var math = new Math();
var sum = math.add(2, 3);
var diff = math.sub(2, 3);

//or

var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);

step-9: By anonymous prototype functions

var Math = function() {
return this;
}

Math.prototype = {} //Note: ‘prototype’ is not present in anonymous function

Math.prototype.add = function(a, b) {
return a + b;
}

Math.prototype.sub = function(a, b) {
return a – b;
}

var math = new Math();
var sum = math.add(2, 3);
var diff = math.sub(2, 3);

//or

var sum = math[“add”](2, 3);
var diff = math[“sub”](2, 3);



Inheritance : Look at this example

function Address() {
return this;
}

Address.prototype.setStreet = function(_street) { this.street = _street; }
Address.prototype.getStreet = function() { return this.street; }
Address.prototype.setCity = function(_city) { this.city = _city; }
Address.prototype.getCity = function() { return this.city;}

function Person() {
return this;
}
Person.prototype = new Address();

function Employee() {
return this;
}
Employee.prototype = new Person();
Employee.prototype = new Account(); //this throws error

Drawback: cannot do multiple inheritance like C++

Lets see how to do it, this is what most of the javascript library is doing,



‘extend’

function extend(childclass, parentclass) {
var _clazz = function() { };
_clazz.prototype = parentclass.prototype;
childclass.prototype = new _clazz();
childclass.prototype.constructor = childclass;
childclass.super = parentclass.prototype;
}

function Person() {
return this;
}

function Address() {
return this;
}

function Employee() {
return this;
}

extend(Employee, Person);
extend(Employee, Address);



Now you need to understand 'instanceof' and '__proto__'

Instanceof : It works like java instanceof

var emp = new Employee();
emp instanceof Employee // returns true

__proto__: It is used to call super class method

function Shape() {
return this;
}

Shape.prototype.draw = function() { …}

function Square() {
return this;
}

Square.prototype = new Shape();
Square.prototype.draw = function() { this.__proto__.draw(); … }

function Cube() {
return this;
}

Cube.prototype = new Square();
Cube.prototype.draw = function() {
this.__proto__.draw();
//.....
}

var c = new Cube();
c.__proto__.draw(); //calls the Square’s draw function
c.__proto__.__proto__.draw(); //calls the Shape’s draw function



What is redefinition ?
Redefinition: Like java invocation handler

function Circle() {
return this;
}

Circle.prototype.draw = function(g) {
g.paint(“circle”, this);
}

var _circle_draw_func = Circle.prototype.draw;
Circle.prototype.draw = function(g) {
//do before ….
_circle_draw_func.call(this, g); //This is like friend function in C++
//do after ….
}

If you don’t do it like this, then you will be replacing the original function with your new function definition



How to construct package ?

if(typeof(com) != “undefined”) {
throw “package ‘com’ is already defined”
}
var com = {};

if(typeof(com.tejas) != “undefined”) {
throw “package ‘com.tejas’ is already defined”
}
com.tejas = {};

if(typeof(com.tejas.lang) != “undefined”) {
throw “package ‘com.tejas.lang’ is already defined”
}
com.tejas.lang = {};

note: you should throw error, otherwise all your definitions on first js file will be replaced by the second js file if both using same packages

Creating function definition on package

com.tejas.web.js.Circuit = new function() {
this.sncs = [];
return this;
}

com.tejas.web.js.Circuit.prototype = { }

com.tejas.web.js.Circuit.prototype.addSncs = function(snc) {
this.sncs.push(snc);
}

Note: Anonymous functions will not have ‘prototype’ map by default.



how to implement Design patterns ?

Singleton

var shapeFactory = function() {
this.createCircle = function() {
return new Circle();
};

this.createSquare = function() {
return new Square();
};
} ();

//but if you need it to be a child of some other function

var shapeFactory;
function ShapeFactory() {
if(!shapeFactory) {
shapeFactory = this;
}
return shapeFactory;
}

ShapeFactory.prototype.createCircle = function() { return new Circle(); }
ShapeFactory.prototype.createSquare = function() { return new Square(); }



How to derive Enum ?

Enum: You have to define it like a singleton object …

com.tejas.lang.TimeUnit = function() {
if(!com.tejas.lang.TIMEUNIT) {
com.tejas.lang.TIMEUNIT = this;
}
return com.tejas.lang.TIMEUNIT;
}

com.tejas.lang.TimeUnit.prototype = {}

com.tejas.lang.TimeUnit.prototype.WEEK = new _TimeUnit(7 * 24 * 60 * 60 * 1000);
com.tejas.lang.TimeUnit.prototype.DAY = new _TimeUnit(24 * 60 * 60 * 1000);
com.tejas.lang.TimeUnit.prototype.HOUR = new _TimeUnit(60 * 60 * 1000);
com.tejas.lang.TimeUnit.prototype.MIN = new _TimeUnit(60 * 1000);
com.tejas.lang.TimeUnit.prototype.SECONDS = new _TimeUnit(1000);

function _TimeUnit(_inSeconds) {
this.seconds = _inSeconds;
return this;
}

_TimeUnit.prototype.convert = function(milli_seconds) { ….. }

new com.tejas.lang.TimeUnit(); //Using: var x = com.tejas.lang.TIMEUNIT.HOUR.seconds;



Constructor

It is a built-in property of the ‘prototype’

Ex: Employee.prototype.constructor

It actually has the reference of the constructing function of the Function

var emp = new Employee.prototype.constructor(); is same like
var emp = new Employee();

Usage: It is used like java reflection kind of feature



Thanks for reading this ....

No comments:

Post a Comment