Prototype Basics: Creating a Javascript Class

Javascript is, by it's nature, not an object oriented language.  However, everything in Javascript is an object.  So what you have are using objects to write procedural code; a truly intriguing concept.  It brings to light that having objects does not make a language object oriented.  Today I want to talk about the other two important concepts of object-oriented programming in Javascript--classes and inheretance.

In object-oriented programming, a Class is used to define an object; that is, it defines what characteristics an object has (its properties) and what it can do (its methods).  Javascript does not allow for either of these concepts in its native implementation (though we can work around this limitation with some clever programming that I'll cover in another article).  Today I want to look at how the Prototype library provides an easy way for developers to create and extend classes and objects of those classes.

We're going to start with creating a basic class.  Most tutorials at this point degenerate into some silly example involving a car, or an animal.  Given that I'm trying here to provide some real world perspective, I want to look at something we might actually try to implement.  In this case, we'll use a photo viewer.  We want to set up a viewer that can be passed a photo and display it.  Then, we'll use inheretance to extend the class to allow for effects.

Creating a Basic Class

var PhotoViewer = Class.create({
    initialize: function(){
    }
});

There are two important things to note in this example:

  1. The Class.create() method is a prototype method that sets up a class for us.  The primary benefit we get from this is that the class can extend another class (which we will do shortly).
  2. When a new object of this class is created, it will automatically call its initialize method.  In Prototype, initialize is the class constructor.

Now we need to add some methods to our class:

var PhotoViewer = Class.create({
    initialize: function(){
        this.photoContainer = $('container');
    },

    showPhoto: function(url){
        var imgEl = new Element("img", {src: url});
        this._show(imgEl);
    },

    _show: function(imgEl){
       this.photoContainer.update(imgEl);
    }
});

So now we've created our first class using Prototype.  The showPhoto() method is a public method that can be called from outside the object.  A URL for an image is passed into it and a new image element is created using that URL.  The _show method is a "private" method that cannot (in this case, should not) be called from outside the object.  It handles the displaying of the element.

Note that Javascript has no concept of public vs. private methods; therefore users could technically call this method wherever they see fit.  The _methodname convention is sometimes used to denote that a class should be considered private by developers and thus not called.

Extending a Class

Now that we have created our basic PhotoViewer class, let's create a class called AdvancedPhotoViewer that extends PhotoViewer to add animation to the image loading.

var AdvancedPhotoViewer = Class.create(PhotoViewer, {
    initialize: function($super){
        $super();
    },
});

There are again two important new concepts introduced here:

  1. Notice that the Class.create() method now has two arguments, the first is the parent class.  By defining a parent class, our class now has access to all of the properties and methods of its parent.
  2. The $super() method calls the method within the parent class that has the same name as the method in the child class.  By calling $super() in the initialize method of our AdvancedPhotoViewer, we call the initialize method of the parent class.  Were we not to call $super() on a method that has an identically named method in the parent class, the method would overwrite the parent method (which there are many times you want to do, which is why this is left for you to decide whether or not you wish to perform all of the tasks from the parent method first). You will see an example of this in a moment.

Now we want to add some animation using Scriptaculous.  We want the element to begin hidden and then appear using a fade-in transition.  For this, we can override the _show() method to call our animation rather than simply calling update():

var AdvancedPhotoViewer = Class.create(PhotoViewer, {
    initialize: function($super){
        $super();
    },

    _show: function(imgEl){
        /* Notice we don't call $super as we want to override the original method */
        this.photoContainer.insert(imgEl.hide());
        new Effect.Appear(imgEl, {fps: 50, duration: 0.5});
    }
});

As you can see, we've added code which will cause the element to fade in rather than simply appearing.  Notice also that even though we never explicitly created it within the AdvancedPhotoViewer class, we can access the this.photocontainer property because we called the parent constructor that defines it.

So there you have it; a brief tutorial on creating and extending classes using Prototype. I hope you found this tutorial helpful. Please feel free to post any questions you may have in the comments section.

Technorati Tags: , , , , , ,