Object Oriented JavaScript
Getting started with JavaScript is no problem. As a hobbyist I remember my delight at being able to hack together some code so that whenever a button was clicked it would change the background colour of my page and make cool “windows style” dialog boxes appear on screen. The very nature of JavaScript allowed me to accomplish such things with relative ease and with limited programming knowledge; the language itself is accessible and forgiving (not having to explicitly declare a variable before using it for example) and other than having to be enclosed within <script></script> tags in the HTML, no code structuring is required or enforced.
Unfortunately it is this inherent flexibility of JavaScript that actually promotes the unmanageable and unscaleable approaches to client side coding we see in many of the web applications on the net today. The majority of JavaScript I have come across personally has been written in such a way as to get something working as quickly as possible, without any consideration for good code design practices. This isn’t necessarily because the developer writing the code was in any way lazy or under pressure to get something working, but because the language allows things to be done this way (and maybe because the developer didn’t know that there were alternatives).
With the emergence of frameworks such as jQuery, MooTools, Prototype, ExtJS, Dojo, ASP.Net AJAX etc and with a lot more focus being placed on UX, JavaScript is steadily being perceived in a different light. Developers, specifically, are realising that JavaScript can be used and structured effectively, that it doesn’t have to be a mess of cross-browser compatible syntax, that OOP principles can be applied, and scalable solutions can be created without cramming everything into in-line global functions.
Some pretty awful things can still be done in JavaScript without trying too hard. I won’t attempt to tell you what you shouldn’t be doing though, instead I’m going to give some examples of the good things that can be done in JavaScript, specifically how to declare and use objects in JavaScript and how to employ good OOP techniques to create maintainable, reusable and easy to understand code.
Object Literal
var monkey = {
name: "Bubbles",
favouriteFood: "Bananas",
makeSound: function() {
alert("OohOohAahAah!");
}
}
monkey.makeSound();
Pros
- Simple: Easy to read, write and understand.
- JSON (a subset of the Object Literal) is commonly used to represent structured data (as an alternative to XML) in AJAX applications.
Cons
- Exists as a single instance, further instances cannot be created.
- Does not support encapsulation.
- Does not support inheritance.
Object Instantiation
function monkey(a) {
this.name = a;
this.makeSound = function() {
alert("OohOohAahAah!");
}
}
var bubbles = new monkey("Bubbles");
bubbles.makeSound();
When a function is called with the “new” operator it serves as a constructor to instantiate a new JavaScript Object type. The “this” keyword refers to the Object instance that the constructor created. By prefixing a property or function name with “this.” makes it a public member and callable by the object’s consumer.
Encapsulation
function monkey(a) {
var favouriteSound = "OohOohAahAah!";
this.name = a;
this.makeSound = function() {
alert(favouriteSound);
}
}
var bubbles= new monkey("Bubbles");
bubbles.makeSound();
Taking advantage of JavaScript closures; the variable favouriteSound has been “hidden” within the object and can be considered a private attribute of the monkey object that has not been publicly exposed using the “this” keyword. Calling myMonkey.favouriteSound returns null/undefined.
function monkey(a) {
var favouriteSound = "OohOohAahAah!";
this.getFavouriteSound = function() {
return favouriteSound;
}
this.setFavouriteSound = function(sound) {
favouriteSound = sound;
}
this.name = a;
this.makeSound = function() {
alert(favouriteSound);
}
}
var bubbles= new monkey("Bubbles");
bubbles.setFavouriteSound = "Good evening.";
bubbles.makeSound();
Public getters and setters for local variables can also be simulated.
Inheritance
function monkey(a) {
this.name = a;
this.makeSound = function() {
alert("OohOohAahAah!");
}
}
function human(a) {
var base = new monkey(a);
base.makeSound = function() {
alert("Get back to work!");
}
return base;
}
var karl = new human("Karl");
karl.makeSound();
When a new human object is instantiated a monkey object is returned, with makeSound redefined to suit the human specialisation.
function human(a) {
var base = new monkey(a);
var makeSound2 = base.makeSound;
base.makeSound = function() {
alert("Get back to work!");
makeSound2();
}
return base;
}
A call to the overridden makeSound function can still be made if needed by creating a reference to it in the human constructor.
Pros
- As “natural” as it gets for traditional OOP programmers.
- Supports encapsulation.
- Supports inheritance.
Cons
- Consumes relatively large amounts of memory when multiple instances of an object are created.
Prototyping
function monkey(a) {
this.name = a;
}
monkey.prototype.makeSound = function() {
alert("OohOohAahAah!");
}
var bubbles = new monkey("Bubbles");
bubbles.makeSound();
The prototype property essentially allows an object’s functionality to be extended.
function monkey(a) {
this.name = a;
}
var bubbles = new monkey("Bubbles");
var clyde = new monkey("Clyde");
monkey.prototype.makeSound = function() {
alert("OohOohAahAah!");
}
bubbles.makeSound();
clyde.makeSound();
An object can be extended even after it has been instantiated.
Encapsulation
function monkey(a) {
this._favouriteSound = "OohOohAahAah!";
this.name = a;
}
monkey.prototype.makeSound = function() {
alert(this._favouriteSound);
}
var bubbles = new monkey("Bubbles");
myMonkey.makeSound();
Although not true encapsulation, the common convention is that members starting with an underscore should be considered private.
Inheritance
function monkey(a) {
this.name = a;
}
monkey.prototype.makeSound = function() {
alert("OohOohAahAah!");
}
human.prototype = new monkey;
human.prototype.constructor = human;
function human(a) {
monkey.call(this, a);
}
human.prototype.makeSound = function() {
alert("Get back to work!");
}
var karl = new human("Karl");
karl.makeSound();
Using the prototype property human is extended with all of monkey’s behaviour, with makeSound redefined to suit the human specialisation.
human.prototype.makeSound = function() {
alert("Get back to work!");
monkey.prototype.makeSound.call(this);
}
A call to the overridden makeSound function can still be made if needed.
Pros
- Supports encapsulation.
- The official way to implement inheritance.
- Allows multiple objects’ functionality to be altered after they have been instantiated. Useful for extending closed libraries.
- Memory efficient when multiple instances of an object are created.
Cons
- Syntax looks crazy to traditional OOP programmers.
Is Object Oriented JavaScript really worth it?
It depends. Personally if all I need to do is apply a jQuery slide animation to a widget then I’ll just wrap a simple function inside a $() so it runs when the DOM is ready. If the widget is slightly more complex however, and is reliant upon user interaction with another element on the page, or perhaps displays some dynamic content based upon where on the page it is positioned, then I’ll consider modelling the behaviour using objects.
If an application evolves to a state where widgets need to interface with each other, a drag and drop shopping cart for example, and business rules also need to be enforced such as voucher discounts, purchase limits etc then the solution should be structured in such a way that it is robust, maintainable and easy to understand – OOP without a doubt facilitates a large share of this.
About this entry
You’re currently reading “Object Oriented JavaScript,” an entry on Web Demon
- Published:
- 4.15.09 / 2pm
- Category:
- JavaScript
- Tags:
- JavaScript, JSON, OOP, Prototype

No comments
Jump to comment form | comments rss [?] | trackback uri [?]