Tuesday, August 21, 2012

Custom Objects in Javascript

I have been using Java for a long time, and for quite some time I was doing web development using GWT (Google Web Toolkit). The beauty of it was that I had my Java object oriented constructs and would not worry about how it gets translated to GWT - let Google take care of it. My knowledge of Javascript was sufficient but not to the extent that I could do heavy web development with it. Later I decided that I have to get a deeper and more thorough understanding of Javascript and this has been a real roller coaster - just at a time where I would think I got something, something came and proved me that I was wrong - that I simply misunderstood.
The culprit for me - Javascript's flexibility, or should I say over-flexibility. Bees that have honey in their mouths, have stings in their tails and he who will gather honey must bear the sting of the bees. Javascript's flexibility is like a wild horse - you have to understand it, so you can play with it. What one needs in Javascript is strong disciplined code conventions and constructs. What I needed from Javascript - a set of code conventions and constructs that will mimic the most popular Java OO concepts.
This post is the first of a series of posts to come and it will cover Custom Objects in Javascript.

In an Object Oriented Programming language like Java, an object is an instance of a class. The class defines member variables and methods that operate on that data. Objects represent instances of the class, and a class represents a blueprint of how a new object is created. In Javascript, this is not the case. Javascript is a prototype-based language and there is no class statement. So, how do we mimick the class behaviour popular in object oriented programming languages like Java? How do we instantiate a new object in Javascript? What is the equivalent of the new keyword in Javascript?

Javascript uses functions as classes


Putting on our Java hat, let us say we have a Car class. The class has properties like price, horsePower and yearMade. We have a constructor for our Car class that looks like this:
public Car(double price, int horsePower, int yearMade) {
    this.price = price;
    this.horsePower = horsePower;
    this.yearMade = yearMade;
}
Let us now introduce a method for this class: getHorsePower that will return the horse power of the Car.
Car c = new Car(19999.99, 140, 2010);
System.out.println(c.getHorsePower());
// will print 140
c is an instance of the Car class and we called the method getHorsePower() on that particular instance.
How can we instantiate an object in Javascript?
Here is how the equivalent would look in Javascript
function createCar(price, horsePower, yearMade) {
    return {
        price: price,
        horsePower: horsePower,
        yearMade: yearMade
    }
}

function getHorsePower(car) {
    return car.horsePower;
}

c = createCar('19999.99','140','2010');
console.log(getHorsePower(c));
// will print 140 on the console

Now, this works but it is not going to win the "Code Beauty" contest. We end up with a lot of functions, and we can't really associate that getHorsePower is defined for the car object only. The way we are going to improve this is by attaching the function getHorsePower as a property of an object like this:
function createAnotherCar(price, horsePower, yearMade) {
    return {
        price: price,
        horsePower: horsePower,
        yearMade: yearMade,
        getHorsePower: function() {
            return this.horsePower;
        }
    }
}
c2 = createAnotherCar('19999.99', '150', '2010');
alert(getHorsePower(c2));
// will alert 150 on the screen​​​​​​
Let us improve this code even further by leveraging the this keyword in Javascript, to make the code look as closely as Java:
function Car(price, horsePower, yearMade) {
    this.price = price;
    this.horsePower = horsePower;
    this.yearMade = yearMade;
    this.getHorsePower = function() { return this.horsePower;};            
}

c3 = new Car('19999.99', '160', '2010');
alert(c3.getHorsePower());
// will alert 160 
Now, that code should look pretty familiar.

No comments: