Object Oriented Programming in JavaScript PART2

Pattern 1: Modules

(This is PART2 of the original post Object Oriented programming in javascript)
The first pattern we’re going to look at is the Module Pattern. Here are a couple of the main features of the module pattern:

  • One-Time Use: Objects that you create with the module pattern are for one-time use. What this means on the web—where you aren’t running JavaScript on more than one page at a time, and not keeping state between refreshes—is that you’ll only have one instance. A module isn’t a little factory that creates objects; it creates a single, specialized object of which there will only be one on a page.
  • No Inheritance: The module pattern doesn’t support inheritance by default. Of course, this doesn’t mean it’s impossible to inherit from it. After all, a module returns a single object, and you can inherit from any object. But that’s outside of the module pattern.
  • Private variable and functions: This feature is almost the whole point of using the module pattern. If you just need a unique object, just use an object literal. However, what if you want to hide values or functionality? An object literal doesn’t offer any way to hide that stuff, so we’ll do it with closure … which is what the module pattern is, in essence.

So, let’s actually create a module.

E.g. 1
JS Bin

We’ll start by creating a module (e.g. 2) that returns a “person” object. Before you start complaining that this isn’t a practical way of doing it, hear me out. We’re going to make a deal here. There’s a reason so many OOP tutorials use physical objects to teach you abstract concepts: it’s easier to understand! If you don’t understand what we’re trying to create, you won’t see the pattern because of the code. So, your part of the deal is that you’ll read through these parts. My part of the deal is that for every physical-object example I use to show a pattern, I’ll do an actual web development example that showcases the same pattern. Because I want to make sure you understand each pattern, and how they are similar or different, we’re going to create the same person object and same web dev object for each pattern.

Okay; with that out of the way, let’s build a module; the basic technique behind the module pattern is the anonymous, self-invoking function ( or immediately-invoked function expression). As you know, we execute this function right away and assign the returned value to the variable. Here’s the setup we start with:

var jill = (function () {

    return {};
} ());

The variable jill will point to that object that gets returned. Before returning that function, we can set up any “private” variables and functions that we want to hide. Anyone using jill won’t be able to see these, but the methods and properties of jill will be able to use them (that’s closure).

So, what will be put in there?

var jill = (function () {
    var first_name = "Jill",
        last_name  = "Taylor",
        age        = 28,
        interests  = [];

    function get_public_age () {
        return age - 5;
    }

    return {
        full_name : function () {
            return first_name + " " + last_name;
        },
        age : get_public_age,
        interests : function () {
            return interests;
        },
        add_interests : function () {
            for ( var i = 0; i < arguments.length; i++ ) {
                interests.push(arugments[i]);
            }
        }
    };
} ());

In this case, we’re starting by setting the values for all the properties as variables under closure. Then, we create a function that returns the “public” age. Notice the difference between the way we’re creating the full_name and the age function: full_name is coded right into the return object, while age references the get_public_age function. Which way should you use? Well, the key here is that—currently—every property and method on the object we’re returning here can be overwritten. This means that if you have another method that calls an overwritten one, you’ll have issues, clearly. For example:

var greeter = (function () {

    return {
        say_hello : function (name) {
            return "Hello " + name + "!";
        },
        greet: function (name) {
            alert( this.say_hello(name) );
        }
    };
}());

greeter.say_hello = "Hi There!";

greeter.greet(); // Fail!

The problem here is that from outside the greeter object we can change the value of greeter.say_hello … and we’ve done that. Now, we can’t be sure that other parts of our object that depend on greeter.say_hello will work properly, and indeed they won’t: greet is no longer reliable.

The way to solve this problem would be to access this function via closure:

var greeter = (function () {
    function say_hello (name) {
        return "Hello " + name + "!";
    }

    return {
        say_hello : say_hello,
        greet: function (name) {
            alert( say_hello(name) );
        }
    };
}());

greeter.say_hello = "Hi There!";

greeter.greet(); // Success!

Now that the user of the object can’t get to say_hello, there’s no fear that they will mess up the functionality of our object. Even by overwriting say_hello, we can’t ruin greet.

So, think about this when writing your module code. Other than that, there’s not much else to say about the code in the module above. You can see how the variables and functions in the closure are protected.

Now, let’s look at a practical example of the module pattern:

var hover_button = ( function () {
    var btn = jQuery("#button"),
        panel=jQuery("#panel");

    function fade_in () {
        panel.fadeIn();
        return this;
    }
    function fade_out () {
        panel.fadeOut();
        return this;
    }

    return {
        bind_events: function () {
            btn.bind("mouseover", fade_in)
               .bind("mouseout", fade_out);
            return this;
        },
        unbind_events: function () {
            btn.unbind("mouseover", fade_in)
               .unbind("mouseout", fade_out);
            return this;
        },
        show: function () {
            fade_in();
            return this;
        },
        hide: function () {
            fade_out();
            return this;
        }
    };
} () );

hover_button.bind_events();

What we’ve made here is a button that fades in a tooltip when it is hovered over. There are two variables: one that references the button itself (btn), and one that references the tooltip (panel). We also have two functions that make it quick and easy to perform the animation on the element.

Inside the object we’re returning, we have four functions: the first two are for binding and unbinding the events that trigger on the button. The second two allow the user of the object to “manually” adjust the state of the button.

To test this code, you’ll have to plug in into some HTML. Try this:

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link href="style.css" rel="stylesheet" />
</head>
<body>
    <div id="button">Hover Over Me!</div>

    <div id="panel">
        This is a tooltip that appears when the button is hovered over.
    </div>

    <script src="jquery.js"></script>
    <script src="module.dom.js"></script>
</body>
</html>

Assuming you store the module above in module.dom.js, this should work fine. See the code included with this tutorial to get the CSS file.

This is a great example of why a module isn’t always the best pattern to use. This is definitely the quickest and easiest pattern to use when coding a tooltip with OOP, but if you want to have more than one tooltip on the page, there are better ways to do it (that we’ll be getting to).

However, if it’s something you only need once, the module pattern is the best way to go. It’s a solid pattern that provides a great ability to hide values and functions … an ability we won’t see again for a while. A lot of the patterns that support inheritance don’t support this hiding-by-closure. However, we’re getting ahead of ourselves. Let’s move on to the next pattern.

Pattern 2: Prototypal Pattern

Let’s move onto the next OOP pattern: the Prototypal Pattern. This is the “object orientedness” that JavaScript offers by default. As we’ll see, it isn’t that great, but it’s worth learning.

Here are the main features of the prototypal pattern:

  • It uses the new keyword to turn normal function into constructors.
  • We can do inheritance via prototypes … but it’s rather clunky.
  • It’s rather ugly in it’s current implementation.

That first one is a big deal. Most other OO languages have you create classes; inside that class, you write a constructor function (difference languages call it different things). In JavaScript, that constructor is just a normal function that is called with the word new in front of it. For example:

new Date();

Date is just a normal function; putting new in front of it does two things to the execution of the function:

  • The keyword this refers to a new object that has been created when this function started. That object inherits from the function’s prototype.
  • The object created (this) will be returned at the end of the function, whether you tell it to be returned or not (The only exception is if you return another object; basically, when using new, you can only return an object).

The thing to realize here is that neither of these things will be true if you don’t use new when calling the function. This is important, because you don’t call the function with newthis will refer to whatever it would normally in this context. In 99% of the cases, this will be the global object, in which case you’ll be “clobbering the global namespace” (quoting Douglas Crockford).

Well, let’s see some code:

function Person (first, last, age) {
    this.first_name = first,
    this.last_name  = last,
    this._age       = age;
    this.interests  = [];
}

There’s more to see, but we’ll start with this. Notice that the way to use this prototypal method is to assign the properties to this inside the function. This function can take parameters to customize the object we’re making. And we don’t have to return anything, since new will do that.

I’m using two common conventions here. First, constructor functions should start with a capital letter, and all other functions should not. This isn’t a rule, but most developers do this as a visual reminder that this isn’t a normal function and you need to call it with new.

The other thing is the property _age. What’s with the underscore? Well, this form of OOP doesn’t offer private variables as we can do with closure in modules. This is an old convention that’s used to let users of the object know that we can’t actually do private variables, so just pretend that you can’t see this. If it starts with an underscore, please respect the object and don’t touch that stuff.

Yes, it’s a bit lame, but it’s what we’ve got to work with if we want to use JavaScript’s native object constructors and inheritance.

Let’s throw out some more code; first, it’s clear that if we don’t use new when calling a constructor function, bad things happen: oil spills, kittens die, and the global object is clobbered. There’s actually something we can do about it: we can make sure it’s called with new:

function Person (first, last, age) {
    if (this === window) {
        return new Person(first, last, age);
    }
    // previous code here . . .
}

This little snippet at the top of our function works wonders: if this is the same thing as window, then we know that new wasn’t used. In this case, we’ll call the function with new (don’t forget to pass in the arguments!), and return that. This way, if the user doesn’t call the function with new, we’ll do it for them. This enforces some safety, but it’s rather unfortunate that we have to do that.

Now let’s talk about prototypes. The prototype is the object is actually a property of the function, called prototype. It’s an object itself, and any properties and methods that this object has will be inherited by the objects created with constructor function.

Always put methods in the prototype, never in the constructor function. This is because if they are in the constructor function, a new copy of the method will be stored in memory for every object you create. If it’s in the prototype, all object will inherit the method. The way this works is as follows: Let’s say you ask object A for method B. If method B isn’t on object A, object A will check the prototype object of its constructor function. If it doesn’t find it there, it will check the prototype of that object, and so on. This way, we only need to have that function once, in the prototype, instead of on each object.

Let’s stick some methods on our Person prototype:

Person.prototype.age = function (age) {
    if (age) {
        this._age = age;
    }
    return this._age -5;
};
Person.prototype.add_interests = function () {
    for (var i = 0; i < arguments.length; i++) {
        this.interests.push(arguments[i]);
    }
    return this;
}

We’ve created two methods here. The first is for getting and setting the age. If we pass in an age, it will set the age to that; either way, it will return the “public” age.The second method is for adding interests to the Person instance’s interests array; it just takes all the arguments passed in and adds them to the array.

It’s important to realize where these methods are placed; they doesn’t go inside the Person function; they go outside it, usually after it. It’s unfortunate that the methods of objects created by JavaScript’s “native” constructor function don’t go with the code that creates the objects themselves. But, that’s what we’ve got to work with.

We can test our work here with the following code:

var jill = new Person("Jill", "Taylor", 28);

jill.interests; // []

jill.add_interests("coding", "drawing");

jill.interests; // [ "coding", "drawing"];

jill.age(29);

jill.age(); // 24

That’s working just fine!

Inheritance with the Prototypal Pattern

The first pattern we looked at (the module pattern) didn’t support inheritance by default. This one does … although, as you’ll see, it’s even sloppier than the disconnected methods we saw above.

Here’s what we want from inheritance: we want the methods of the object type we’re inheriting from to be available in our new objects without having to re-write them. As we’ve discussed, this makes it easier to manage our code.

So, let’s say we want to make SuperHuman objects. We’ll have it inherit from Person, as well as add some of its own functionality.

Let’s start, as usual, with our constructor:

function SuperHuman(first, last, power) {
    if (this === window) {
        return new SuperHuman(first, last, power);
    }
    this.first_name = first;
    this_last_name  = last;
    this.power      = power;
    this.interests  = [];
}

There’s nothing here to catch you off guard. So, let’s do this inheritance thing.

As you might guess, it’s the prototype of our “child” constructor that does the inheriting:

SuperHuman.prototype = new Person();
SuperHuman.prototype.constructor = SuperHuman;
SuperHuman.prototype.wield_power = function () {
    return this.power.toUpperCase() + " to the rescue!";
}

We start by setting the prototype of SuperHuman to an instance of Person; that’s how the inheritance is done. Since every instance of Personhas access to the Person methods on the prototype, our SuperHuman instances have the same access now. Notice that we’re completely over-writing the old SuperHuman.prototype object with the new instance of Person. But in doing that, we’ve removed an important link. Therefore, we have to set the prototype’s constructor property equal to the constructor function. It’s important to do this whenever completely over-writing a prototype object with a new object. That constructor link will point to the constructor of the inherited class. To be honest, you won’t often run into cases where this causes issues. But, if you don’t reset the constructor property, then a number of things won’t work, like this:

var sh = new SuperHuman();
sh.constructor; // Person

sh.constructor.prototype.weild_power; // doesn't exist, because you're looking at the Person prototype

After we correct that link, we can add any custom methods for our objects. Now, our SuperHuman is ready to create objects.

var joe = new SuperHuman("Joe", "Plumber", "Draino");

joe.power; // "Draino";

joe.add_interests("Plumbing");

joe.interests; // [ "Plumbing" ]

joe.wield_power; // "Draino to the rescue!"

As you can see, we can use methods from both Person and SuperHuman.

Now, let’s move on to creating a practical thing: we’ll take the tooltip that we created via the module pattern and remake it prototypally. Then, we’ll inherit from that and enhance it.

So, here’s our new constructor:

function Tooltip_Button (btn, panel) {
    if (this === window) {
        return new Tooltip_Button(btn, panel);
    }
    this.button = jQuery(btn);
    this.panel  = jQuery(panel);
}

It’s a pretty basic constructor; now, let’s look at the prototype object:

Tooltip_Button.prototype = {
    constructor : Tooltip_Button,

    show: function () {
        this.panel.show();
        return this;
    },
    hide: function () {
        this.panel.hide();
        return this;
    },
    bind_events: function () {
        var that = this;
        this.button.bind("mouseover.Tooltip_Button", function () { that.show.call(that) });
        this.button.bind("mouseout.Tooltip_Button", function () { that.hide.call(that) });
        return this;
    },
    unbind_events: function () {
        this.button.unbind(".Tooltip_Button");
        return this;
    }
};

This might catch you off guard; but remember that the prototype is just a normal object, so we can assign a new object literal as the prototype and that’s perfectly legal. We can’t forget to reset the constructor property. Then, we add the show and hide functions to actually show and hide the tooltip. Then, we have two extra maintenance functions to bind and unbind the events. We can test this like this:

var tb = new Tooltip_Button("#button", "#panel");
hb.bind_events();

Throw this all in a script, link it up to the HTML we had earlier, and run this in a browser. You should see the tooltip show up when you hover over the button. However, it’s not fading, like we had before. Therefore, we’ll create another constructor that inherits from our first one; this way, we can add only the functionality that’s different, while inheriting what’s the same.

Here’s our constructor:

function Fading_Tooltip_Button (btn, panel) {
    if (this === window) {
        return new Fading_Tooltip_Button(btn, panel);
    }
    this.button = jQuery(btn);
    this.panel  = jQuery(panel);
}

You might be noticing something really unfortunate: even though the constructor for this object is exactly the same as the object it’s inheriting from, we have to write it all over again.

Now, let’s inherit and add our new features:

Fading_Tooltip_Button.prototype = new Tooltip_Button();
Fading_Tooltip_Button.prototype.constructor = Fading_Tooltip_Button;
Fading_Tooltip_Button.prototype.show = function () {
    this.panel.fadeIn();
    return this;
}
Fading_Tooltip_Button.prototype.hide = function () {
    this.panel.fadeOut();
    return this;
}

After we inherit and re-add the constructor property, we can over-write the show and hide functions; this time, we’re using jQuery’s fadeInand fadeOut functions to do the showing and hiding. It’s that simple: now we have a tooltip that will fade in and out.

Test it by doing something like this (assuming you add it to the code above):

hb.unbind_events();
var hb2 = new Fading_Tooltip_Button("#btn", "#panel");

hb2.bind_events();

Once of the benefits here is that if we found a bug in the shared code—say, in the unbind_events function—we would only have to change it once.

So, now we’ve covered two ways of creating objects with JavaScript. Let’s move on to the third pattern now.

Pattern 3: Classical Pattern (Continued in Part3..)

Loading Facebook Comments ...

2 thoughts on “Object Oriented Programming in JavaScript PART2”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>