JavaScript Guides Advanced


 



Object-Oriented JavaScript

Following on from my earlier post, “Object-Oriented Concepts,” it’s time we started to have a look at some
examples of execution. I’m going to start with Javascript because I believe this to have widest appeal - PHP, as a
server-side language, is probably of interest to fewer developers so I’ll cover it later.

So without further ado, here’s how to objectify your javascript…

 

Objects in Javascript

Although Javascript shouldn’t be classed as an object-oriented language, pretty much everything within it is object
based; from DOM scripting (Document Object Model) through to specific built-in objects such as Image and Date.
This basically means that we can adopt some OOP concepts but not all.

Javascript handles objects in a number of ways; a developer can define an object and then instantiate with the new
operator, a developer can declare an object on the fly using the object literal or a developer can extend an
existing object (either built-in or user-defined) using its prototype.

In fact, even data-types that can be declared literally, such as arrays and strings, can also be declared as objects.
This is mainly so that object methods can be applied to literal values when needed. Javascript does this by
temporarily converting your literal into an object. A good example would be the String.length method.

Sounding complicated? Don’t worry, it’s really very easy. Let’s start getting our hands dirty…

The Object Literal

In programmer-speak, a “literal” is any value declared literally. Good examples would be string literals, array
literals and boolean literals - the literal is the part after the “=” assignment operator:

// String literal  var my_string = "2468 This is a string";  // Array literal  var 
my_array = ['element1', 'element2', 'elephant']; // Boolean literal var my_boolean =
true;

As a developer, you probably use these methods day-in, day-out; it still amazes me, however, how many
programmers I speak to that don’t know the correct terminology!

In Javascript, we can also declare objects as a literal:

function getArea(radius)  {    // return the radius of our circle using the    // PI 
attribute of the built-in Math object return (radius * radius) * Math.PI; } var
circle = { radius : 9, getArea : getArea(this.radius) };

Here we’ve defined an object, circle, with a radius of 9. If we wanted to obtain the area of our circle, we could use
the following line of code:

var my_radius = circle.getArea();

Fantastic! We’ve got ourselves a circle; but what happens when we want to declare more circles, all with varying
radii?

Imagine we want to create lots of circle objects using our object as a base - if we’ve declared using the object
literal, we’re not able too. That’s the difference between objects and classes ; if we want our object to behave
more like a class (which, unfortunately, aren’t really supported in Javascript even though we can mimic the
behaviour), we need to use objects that utilise the new operator.

Note: For more information on the object literal, I recommend reading Chris Heilmann’s “Show Love to The
Object Literal,” and Dustin Diaz’s “JSON for the Masses.”

The new Operator

The new operator creates an instance of any built-in or user-defined object - basically allowing us to re-use a user-
defined obect (much like the behaviour of a class). Here are a couple of examples using built-in objects:

// Create a date object  var obj_today = new Date();  // Preload an image using the 
Image object var obj_supper = new Image(); obj_supper.src = 'thelastsupper.jpg';

Take note that Javascript’s built-in objects do not always use a proper class interface - ie. you can set attributes
without using a method. In most OOP languages this is considered bad practice and you can often prevent it with
the use of access modifiers (public, private, protected). Even though Javascript let’s us get away with this method
when using its built-in objects, I personally tend to write a proper interface for my own objects.

Ok, so that’s how you declare using the built-in objects, but what about something user-defined?

When using the new keyword to declare user-defined objects, the objects require a constructor. Object structure
(including an object’s constructor) is handled somewhat differently to most languages in Javascript. Here’s the
syntax for defining this type of object:

function circle(radius)  {    this.radius = radius;    this.getArea = getArea;    // 
Don't forget that a constructor should // always retain a valid state - so it should
// always return true return true; } function getArea() { // return the radius
of our circle using the // PI attribute of the built-in Math object return
(this.radius * this.radius) * Math.PI; }

In the example above, you’ll notice that the syntax is almost completely identical to declaring a function. This
function is the constructor of our object and attributes and methods are declared within it, using the this keyword.

Notice the Math object doesn’t need to be instantiated before we can use it - this is simply because it’s special and
is always available for use.

We can now instantiate our object using the new operator as before:

var obj_pizza = new circle(9);

And we can work out the area of our circle using the following line of code:

var flt_area = obj_pizza.getArea();

Encapsulation

There is one problem with the above definitions of an object, however, and that’s the lack of encapsulation. If we
were to include another piece of code that used a getArea() function (for instance a triangle object), our circle
object’s getArea() method would be over-written. To better encapsulate our methods, we can define our objects
either literally like so:

var circle = {    radius : 9,    getArea : function()    {      return (this.radius * 
this.radius) * Math.PI; } };

Or non-literally like so:

function circle(radius)  {    this.radius = radius;    this.getArea = function()    {      
return (this.radius * this.radius) * Math.PI; }; return true; }

In both cases this limits the scope of each getArea() method to each circle object.

Inheritance and prototype

The prototype property is a useful feature in Javascript - it basically allows us to add attributes or methods to an
object. This is a form of inheritance.

As a quick example of prototype in use, let’s add a function to work out circumference:

function circle(radius)  {    this.radius = radius;    this.getArea = function()    {      
return (this.radius * this.radius) * Math.PI; }; return true; } // Add our
new method circle.prototype.getCircumference = function() { return this.radius *
Math.PI * 2; } // Instantiate our object var my_pizza = new circle(9); // Call our
new method var flt_pizza_circ = my_pizza.getCircumference();

“But wait, ” I hear you cry, “what if we want to inherit and entire object?”

Not a problem, prototype can handle this like so:

// Declare two objects - we're going to want Lion to  // inherit from cat  function cat
() { this.eyes = 2; this.legs = 4; this.diet = 'carnivore'; return true;
} function lion() { this.mane = true; this.origin = 'Africa'; return true;
} // Now comes the inheritance lion.prototype = new cat(); // We can now obtain
lion.diet var simba = new lion(); var simba_diet = simba.diet;

Ok, so now that we understand inheritance (you do understand, right?), let’s take a look composition.

Composition

Association

Association, in Javascript, is pretty straight forward. Here’s an example:

// Define an object  function brick()  {    return true;  }  // Define an object  
function wall() { this.brick1 = new brick(); this.brick2 = new brick();
this.brick3 = new brick(); return true; }

Just like the pseudo-code example in my earlier post, we can see that the object “wall” now contains three instances
of the “brick” object. This is association - the wall object “has” three bricks.

Now let’s take a look at aggregation.

Aggregation

Aggregation, as a relationship, is reliant on the ability to pass object and function parameters by reference. This
basically means that a parameter represents the ACTUAL object passed and not just a copy. Thankfully,
Javascript handles all parameters in this way - which makes our aggregation relationship nice and easy:

function person  {    return true;  }  function car(driver)  {    this.driver = driver;    
return true; } var me = new person(); var myMotor = new car(me);

This relationship allows us to “use” the “me” object within our “myMotor” object. We could also use the “me”
object in any other objects that require it - and we’d only need that single instantiation. This is immensely helpful
when we’re using objects that control behaviours such as XmlHttpRequest.

Update: Thanks to Jonathan Snook, I’ve recently discovered that Javascript doesn’t pass all parameters by
reference - in fact working out how Javascript has handled your parameter can be quite confusing. In our particular
case, the parameter is passed by reference because it is an object. When we’re not working with objects, this
might not be the case. For more detailed information, please take a look at Jonathan’s excellent article, “Javascript:
Passing by Value or by Reference.”

Polymorphism

Due to it’s object-based nature, Javascript handles polymorphism very well. Take a look at the following example:

function circle(radius)  {    this.radius = radius;    this.getArea = function()    {      
return (this.radius * this.radius) * Math.PI; }; return true; } function
rectangle(width, height) { this.width = width; this.height = height;
this.getArea = function() { return this.width * this.height; };
return true; }

Both objects have a getArea() method, but both methods carry out different calculations. This is polymorphism in
action.

Summary

So that’s a brief guide to adopting OOP practices in Javascript; I think you’ll agree that it adds real power when
dealing with complicated scripts. However, that raises a common issue with OOP - you shouldn’t just use it for the
sake of it. In fact, I often find that developers who are using these practices for everything are often the same
developers who don’t understand the concepts fully.

My next OOP post will be regarding object-oriented PHP but, after an inquisitive email from Nate Logan, I also
intend writing a piece about abstraction - the practice of reducing a process down to it’s root concepts and
modelling them in the programming language of your choice.





JavaScripts Guides: Beginner, Advanced
JavaScripts Tutorials: Beginner, Advanced



[Home] [Templates] [Blog] [Forum] [Directory] JavaScript Guides Advanced -
Object-Oriented JavaScript