An Object Lesson In JavaScript

Find out how JavaScript objects can substantially speed up code development and deployment.

...Nothing But The Truth

It's sad but true - there are a whole bunch of people out there who think that JavaScript is only good for image swaps and ticker tapes.

I'm here to tell you that it ain't so.

Yes, JavaScript is a client-side scripting language; most often, it's used to make objects fly around on a Web page, or validate the data entered into an HTML form. But, once you go beyond the obvious and dig a little deeper, it will become obvious that there's a whole lot more to this simple, easy-to-learn language.

In order to illustrate this, I'm going to spend the next few pages exploring some of the object-oriented constructs available in JavaScript. You didn't know you could use object-oriented concepts in JavaScript?! Shock, shock! Horror, horror!

Now, JavaScript doesn't offer nearly as much power and flexibility in its object model as do languages like Java and Perl; however, as you will see, even the limited features available can come in quite handy at times. And, with a little bit of thought, a clever developer like you can use JavaScript objects to substantially reduce the time spent on code development and testing...while simultaneously gaining the respect of your colleagues and the admiration of the pretty girl next door.

Let's get on with it, shall we?

Object Lessons

Before we get into object construction, a quick primer for all those of you who are new to the weird and wonderful world of objects.

In JavaScript, a "object constructor" is simply a set of program statements which perform a specific task - they lay down the basic rules for an object, specifying what it can and cannot do. A typical object constructor contains both variables and functions, and serves as the template from which to spawn specific instances of that object.

Every object constructed from the template has certain characteristics, or "properties", and certain pre-defined functions, or "methods". These properties and methods of the object correspond directly with the variables and functions within the object definition.

Once an object has been defined, JavaScript allows you to spawn as many instances of the object as you like. Each of these instances is a completely independent object, with its own properties and methods, and can thus be manipulated independently of other objects.

Now, you're probably wondering whether this is a little redundant, since JavaScript also allows you to create your own functions and use them wherever required in your code. And you're correct, to some extent - if you're only planning to spawn a single object, a function will work just as well.

But there are situations where you need to spawn more than one instance of an object - for example, multiple menu trees, multiple image swaps, or multiple ticker tapes (you'll see multiple Calendar objects a little further down). In such a situation, objects are preferred, since each instance comes with its own variables and functions, and thus can be manipulated without affecting other variables within the program.

Objects also help you keep your code modular - you can define an object constructor in a separate file, and include that file only in the pages where you plan to use the object - and simplify code changes, since you only need to edit a single file to add new functionality to all your spawned objects.

Sumthing New

You've probably already used JavaScript objects before - for example, the code

<script language="JavaScript">
a = new Image();
</script>

creates a new instance of the Image object, while

<script language="JavaScript">
x = new Date();
</script>

creates a new instance of the Date object.

JavaScript comes with numerous built-in objects, each with pre-defined methods and properties...but what if you want to roll your own?

Well, it isn't very difficult - as a matter of fact, it's almost identical to writing a JavaScript function.

<script language="JavaScript">

// object constructor
function Sumthing() {
}

</script>

You can create an instance of the Sumthing object like this:

<script language="JavaScript">

// object instance
obj = new Sumthing();

</script>

Note the all-important "new" keyword - this is how JavaScript knows that you're trying to create an instance of an object, rather than merely running a function.

The code above creates an instance named "obj" of the object Sumthing. You can verify that it is indeed an object, oh yes, by popping up an alert().

<script language="JavaScript">
obj = new Sumthing();
alert(obj);
</script>

Alpha Radiation

So far, Sumthing's just sitting around looking pretty - it doesn't actually do anything yet. Let's fix that by modifying it to accept some arguments.

<script language="JavaScript">

// object constructor
function Sumthing(num1, num2) {
// object properties
this.alpha = num1;
this.beta = num2;
}

</script>

The object Sumthing now has two properties, "alpha" and "beta". With this, it is possible to create an instance of the object Sumthing, and pass it two parameters ("num1" and "num2"), which are then stored as object properties ("alpha" and "beta"). Note my use of the "this" keyword, which provides a convenient way to access variables (and functions) which are "local" to the object constructor.

Let's take it for a spin.

<script language="JavaScript">
obj = new Sumthing(2, 89);
alert("alpha is " + obj.alpha);
alert("beta is " + obj.beta);
</script>

And you should see something like this:

Add()ing Some More

Just as you can define object properties, it's also possible to define object methods - essentially, simple JavaScript functions. A little more evolution, and the Sumthing object now sports an Add() method, which adds the values stored in "alpha" and "beta".

<script language="JavaScript">

// object constructor
function Sumthing(num1, num2) {

// object properties
this.alpha = num1;
this.beta = num2;

// object methods
this.Add = Add;
}

// object method Add() - add arguments
function Add() {
sum = this.alpha + this.beta;
return sum;
}

</script>

A couple of interesting things here. First, the object method Add() is actually defined outside the object constructor block, though it references object properties using the "this" keyword. And second, just as object properties are defined using "this", object methods need to be defined in the same manner - witness my addition of

function Sumthing(num1, num2) {
...
// object methods
this.Add = Add;
...
}

to the object constructor block.

Wanna see how it works? Take a look at the code

<script language="JavaScript">
obj = new Sumthing(2, 89);
alert("The sum of " + obj.alpha + " and " + obj.beta + " is " + obj.Add());
</script>

and the output.

And now that your object constructor is all ready to go, let's see a quick demonstration of how you can use it to spawn multiple instances of the same object, each operating independently of the other.

<script language="JavaScript">
// one object
obj1 = new Sumthing(2, 89);
alert("The sum of " + obj1.alpha + " and " + obj1.beta + " is " + obj1.Add());

// another one
obj2 = new Sumthing(546, 67);
alert("The sum of " + obj2.alpha + " and " + obj2.beta + " is " + obj2.Add());

// and a third one
obj3 = new Sumthing(2364237, 283457);
alert("The sum of " + obj3.alpha + " and " + obj3.beta + " is " + obj3.Add());
</script>

Now that is cool!

Turning Up The Heat

Here's another example, this one a Thermometer object which allows you to convert between different temperature scales.

<script language="JavaScript">

// constructor
function Thermometer(degrees, scale)
{

// methods
this.convertToCelsius = convertToCelsius;
this.convertToFahrenheit = convertToFahrenheit;
this.raiseTemp = raiseTemp;

// action to take
if (scale == "f" || scale == "F")
    {
    this.scale = scale;
    this.degreesF = degrees;
    this.degreesC = 0;
    this.convertToCelsius();
    }
else
    {
    this.scale = scale;
    this.degreesF = 0;
    this.degreesC = degrees;
    this.convertToFahrenheit();
    }
}

// conversion functions
function convertToCelsius()
{
this.degreesC = (5.0/9.0) * (this.degreesF - 32.0);
}

function convertToFahrenheit()
{
this.degreesF = ((9.0/5.0) * this.degreesC) + 32.0;
}

// method to raise temperature
function raiseTemp(num)
{
this.degreesF += num;
this.degreesC += num;
}

</script>

Nothing too fancy here - the constructor simply creates an object, initializes it with a temperature and temperature scale, and runs a conversion function to obtain the equivalent temperature in the other scale. A raiseTemp() method is included to demonstrate how object properties can be altered.

It should be noted here that it is also possible to directly adjust the object properties without using the raiseTemp() method. I say "technically", because it is generally not advisable to do this, as it would violate the integrity of the object; the preferred method is always to use the methods exposed by the object to change object properties. By limiting yourself to exposed methods, you are provided with a level of protection which ensures that changes in the object constructor code do not have repercussions on your code.

And here's how you could use the object in an HTML document.

<script language="JavaScript">

// create an object instance
a = new Thermometer(98.6, "f");

// access object properties
alert("Temperature in Fahrenheit is " + a.degreesF);
alert("Temperature in Celsius is " + a.degreesC);

// execute object methods
a.raiseTemp(10);
alert("Temperature in Fahrenheit is " + a.degreesF);
alert("Temperature in Celsius is " + a.degreesC);

</script>

Here's the result:

Room With A View

Just as you can pass parameters to an object, it's also possible to pass it another object. Consider the following example, which consists of two object constructors - the second one is set up to accept an object as parameter.

<script language="JavaScript">

// Room object
// accepts area (sq. ft.) and colour (walls) as parameters
function Room(area, colour)
{
this.area = area;
this.colour = colour;
}

// House object
// accepts price as parameter
function House(price, room)
{
this.price = price;
this.obj = room;
}

</script>

Here's how you might use it:

<script language="JavaScript">
Kitchen = new Room(500, "white");
DiningRoom = new Room(600, "white");

RedGables = new House(89000, Kitchen);
alert(RedGables.obj.area);
</script>

In this case, the newly-created instance of the Room object, "Kitchen", is passed to the House object "RedGables". Using a hierarchical structure, it is possible to drill down through the House object to the Room object and obtain the value of a specific object property. This is similar to the manner in which many DOM objects are accessed.

Construction Crew

There are a couple of other interesting things about JavaScript objects. For example, should you ever need to, you can obtain complete information on an object's constructor via the "constructor" property. The following example demonstrates how it can be used with the Sumthing object constructor.

<script language="JavaScript">

alpha = new Sumthing(23, 865);
alert("The object constructor for alpha is " + alpha.constructor);

</script>

Here's what it looks like:

And you can use the "prototype" keyword to add new object properties to an already existing object - consider the following addition to the Room object you just saw:

<script language="JavaScript">

// Room object
// accepts area (sq. ft.) and colour (walls) as parameters
function Room(area, colour)
{
this.area = area;
this.colour = colour;
}

Room.prototype.direction = "east";

</script>

This would add an object property named "direction", with value "east" to the Room object constructor. And when you try to access the object property

<script language="JavaScript">
Kitchen = new Room(1000, "green");
alert(Kitchen.direction);
</script>

you should see this:

The "prototype" keyword can be used to add object methods as well - try it yourself and see!

A Hot Date

And finally, here's another example of just how useful JavaScript objects can be. I've put together a Calendar object, which displays a neat monthly calendar for any month you care to name - simply specify the month and year as object properties, and let the constructor take care of the rest.

<script language="JavaScript">
/*  Calendar object, calendar.js
    Usage:
    obj = new Calendar(mm, yyyy);
    created 15.Mar.2001

    copyright Melonfire, 2001. all rights reserved.
    http://www.melonfire.com/community/columns/trog/

    demonstration only - not meant for production enviroments!!
*/

// constructor
function Calendar(month, year)
{

// array of day names
this.days = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");

// array of month names
this.months = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

// array of total days in each month
this.totalDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

// object properties - month and year
// correction for zero-based array index
this.month = month-1;
this.year = year;

// leap year correction
if (this.year % 4 == 0)
    {
    this.totalDays[1] = 29;
    }

// temporary variable - used later
this.rowCount = 0;

// object method
this.display = display;

// automatically run method display() once object is initialized
this.display();
}

// function to display calendar
function display()
{
// create a Date object
// required to obtain basic date information
// get the first and last day of the month - boundary values for calendar
obj = new Date(this.year, this.month, 1);
this.firstDayOfMonth = obj.getDay();
obj.setDate(31);
this.lastDayOfMonth = obj.getDay();

// start table
document.write("<table border=0 cellpadding=2 cellspacing=5>");

// month display
document.write("<tr><td colspan=7 align=center><font face=Arial size=-1><b>" + this.months[this.month] + " " + this.year + "</b></font></td></tr>");

// day names
document.write("<tr>");
for (x=0; x<7; x++)
{
document.write("<td><font face=Arial size=-2>" + this.days[x].substring(0,3) + "</font></td>") ;
}
document.write("</tr>");

// start displaying dates
// display blank spaces until the first day of the month
document.write("<tr>");
for (x=1; x<=this.firstDayOfMonth; x++)
{
// this comes in handy to find the end of each 7-day block
this.rowCount++;
document.write("<td><font face=Arial size=-2>&nbsp;</font></td>");
}

// counter to track the current date
this.dayCount=1;
while (this.dayCount <= this.totalDays[this.month])
{
    // use this to find out when the 7-day block is complete and display a new row
    if (this.rowCount % 7 == 0)
    {
    document.write("</tr>\n<tr>");
    }

// print date
document.write("<td align=center><font face=Arial size=-1>" + this.dayCount + "</font></td>");
this.dayCount++;
this.rowCount++;
}
// end table
document.write("</tr></table>");
}

// eof
</script>

Here's a brief explanation of what this does, and how it does it.

The first few lines set up the arrays containing month and day names, and the total number of days in each month. A simple equation is used to find out whether the year in question is a leap year, and appropriate modification made to the total number of days for February if so. Control then passes to the object method display(), which is responsible for actually writing the calendar to the page.

With a little help from the Date object and a couple of temporary variables, a table is created and filled with the days of the month. The document.write() method takes care of setting up the <table>, <tr> and <td> tags, and printing date information into the table cells.

Here's an example of how you could use this object.

<html>
<head>
<script language="JavaScript" src="calendar.js"></script>
</head>

<body bgcolor="white">
<script> obj1 = new Calendar(2, 2005); </script>
<script> obj2 = new Calendar(7, 2001); </script>
</body>
</html>

And here's what you'd see:

And that's about it. I hope the examples in this article gave you a better appreciation for the usefulness of JavaScript objects, and perhaps even sparked a few ideas on how you can use them in your development activities. If you have questions, comments or large amounts of money for me, send me some email - and come back next time for more!

Note: All examples in this article have been tested on Internet Explorer 5.0 and Netscape Communicator 4.76. Examples are illustrative only, and are not meant for a production environment. YMMV!

This article was first published on20 Mar 2001.