Dec 21 2006

Creating Classes with Prototype
Comments Off on Creating Classes with Prototype

Note: Examples make use of Joe Hewitt’s Firebug extension for Firefox. If you do not have this software, feel free to follow along by replacing console.log(msg) with a much less elegant option such as alert(msg).

Now that Ajax has reared its ugly head, developers are awakening to the powerful behavior that Javascript can add to their applications. Javascript’s very unfamiliar object syntax is one of the reasons it had previously been avoided like the plague. Since Javascript has a prototype-based inheritance, creating objects is quite different than the class-based inheritance scheme we are used to.

Simple Javascript Objects

Creating an object in Javascript is actually quite simple using the new Object syntax, and we can add properties on the fly using the . operator.

var d = new Object();
d.name = 'Tripod';
d.legs = 3;
 
console.log("My Dog "+d.name+" has "+d.legs+" legs");

Methods are added to an object using the same syntax as properties. In fact methods are simply functions assigned as properties. Keep in mind that functions in Javascript are actually objects, and can be passed around and assigned just like any other data type. In this case, we will attach a function to the run property of our object.

d.run = function() {
  console.log('hobble... hobble');
}
d.run();

Another option for creating objects is using Javascript’s object literal syntax. This uses a key/value pair definition within curly braces to define the object.

var d = {
  name: 'Tripod',
  legs: 3,
  run: function() {
    console.log('hobble... hobble');
  }
}

Object Constructors

Although simple, these ways of creating objects becomes repetitive when we want to create another object. What we really want to do is create a template for an object that stores all of this information together so that we can reuse it. This is done in javascript by creating a constructor function. This function lets you pass in variables to define the state of your object similar to how you would in a class. A constructor looks just like any other Javascript function except for a few constructor commandments:

  • The function name shall be capitalized (not required but highly recommended).
  • The function shall be called through use of the new construct.
  • The function shall make use of the this keyword.
function Party(people, beers) {
  this.people = people;
  this.beers  = beers;
}

We can now create a Party object using the new construct. This will create a reference to a new Javascript object, and pass that object into the function to be referenced with the this keyword.

var p1 = new Party(3, 9);
var p2 = new Party(11, 60);
 
console.log("party 1 has: " + p1.people + " peeps");
console.log("party 2 has: " + p2.people + " peeps");

We can now create lots of Parties in a more efficient method than before. This is great, but these objects are pretty useless without any behavior. Let’s add a method to our parties to see if any of them are kickin.

Party.prototype.status = function() {
  return this.beers/this.people > 5 ? 'kickin' : 'lame';
}
console.log("party 1 is: " + p1.status());
console.log("party 2 is: " + p2.status());

Earlier we created a method by assigning a function directly to the property of an object, but this time we have assigned it to Party‘s prototype property. This is where Javascript gets a bit confusing. The Party constructor has an extra property that is always defined by default: the prototype object. This is like a parent object of all Party objects that gets shared between each instance. Since methods will remain the same for all Party instances, we don’t want to waste memory by creating copies for each instance. The prototype object gives us a space to share those properties between all instances. We can do a similar thing with any property that will remain constant in all instances.

Party.prototype.music = true;
console.log("party 1 tunes: " + p1.music);
console.log("party 2 tunes: " + p2.music);

Because it’s no party without tunes. Now we have a template to create a party that always has music, and we can check if it’s a party worth attending by using the status() method. The entire definition of our object template like so:

function Party(people, beers) {
  this.people = people;
  this.beers  = beers;
}
Party.prototype.music  = true;
Party.prototype.status = function() {
  return this.beers/this.people > 5 ? 'kickin' : 'lame';
}

It’s definitely not going to win a beauty pageant.

The Prototype Way

This is where the Prototype library steps in to help clean up a little of the mess. One of base features of Prototype is making the creation of an object template nicer using the Class.create() function. This function takes the mess above, and structures it in a way that is more familiar to us class-based programmers.

Party = Class.create();
Party.prototype = {
  music: true,
 
  initialize: function(people, beers) {
    this.people = people;
    this.beers  = beers;
  },
  status: function() {
    return this.beers/this.people > 5 ? 'kickin' : 'lame';
  }
}

This takes all of this logic and puts it into a nice construct that keeps it all together with a unified constructor function named initialize. Prototype does a little magic behind the scenes so that you can initialize your objects in the same way you previously did with the new operator.

var p1 = new Party(3, 9);

Let’s take a look at what Prototype is doing here by sneaking a peak at the source.

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

We see here that the Class object consists of a single
method, create(). When we call this method it returns us
a function object.

Remember earlier when we created the Party constructor function using Javascript’s native syntax? It was essentially a function used to set the properties of new objects.

Native Construction

This function returned by create() is actually this same constructor function. The difference is that it delegates setting the object properties to the initialize method.

Prototype Construction

  1. You create a Party object with the new
    construct, and pass in the the properties we want to set. This executes
    the constructor function that was created when we called
    Class.create().
  2. The constructor function calls Javascript’s apply
    function on initialize. The apply function lets you
    execute a method in the context of a different object. In this
    case we need to execute the initialize method, but we
    want it to use our newly constructed object from our constructor method
    as this when it executes.

While a little more complex behind the scenes, this code provides a nice abstraction that allows us to code in a style we are more familiar with. We welcome anything that makes our code a little easier to read or maintain.

Sorry, the comment form is closed at this time.