Member Sign In
Not a member?

A Wired.com user account lets you create, edit and comment on Webmonkey articles. You will also be able to contribute to the Wired How-To Wiki and comment on news stories at Wired.com.


It's fast and free.

Webmonkey is a property of Wired Digital.
processing...
Join Webmonkey

Please send me occasional e-mail updates about new features and special offers from Wired/Webmonkey.
Yes No

Please send occasional e-mail offers from Wired/Webmonkey affiliated web sites and publications, and carefully selected companies.
Yes No

I understand and agree that registration on or use of this site constitutes agreement to Webmonkey's User Agreement and Privacy Policy.
Webmonkey is a property of Wired Digital.
processing...

Retrieve Sign In

Please enter your e-mail address or username below. Your username and password will be sent to the e-mail address you provided us.

or
Webmonkey is a property of Wired Digital.
processing...

Welcome to Webmonkey

A private profile page has been created for you.
As a member of Webmonkey, you can now:
  • edit articles
  • add to the code library
  • design and write a tutorial
  • comment on any Webmonkey article
Close
Webmonkey is a property of Wired Digital.

Sign In Information Sent

An e-mail has been sent to the e-mail address registered in this account.
If you cannot find it in your in-box, please check your bulk or junk folders.
Sign In
Webmonkey is a property of Wired Digital.

Make OOP Classes in JavaScript

/skill level/
/viewed/
0 Times

Contents

Introduction

Anyone who has tinkered with the prototype model in JavaScript to produce classes as we know them in other languages has generally left web programming all together and taken up a career as a bus driver. There are a coterie of frameworks designed specifically to address this problem. But what if you're not wild about frameworks, preferring instead to build tools specifically suited to your needs and style? For you, there is some black magic that can revolutionize the way you interact with the current JavaScript standard (someone please thaw me out when the 2.0 standard is implemented in June 2134, or whatever the projected date is).

What you'll need

a text editor and a web browser

Steps

Meet the encapsulated JavaScript function! More than a function, less than a traditional OOP class, but super useful and a cinch to make. All you really need is:

function someObj() {
    function someMethod() {
        alert('boo');
    }
}

o_obj = new someObj();

As the name suggests, and encapsulated JavaScript function is just that - one function encapsulated within another. If you dropped this into a page and ran it in the browser, you'd have a big load of nothing. But whip out the "this." keyword, and things get interesting. In JavaScript "this." refers to the owner of an object, be it variable, function, or DOM element. For our purposes, "this." refers to an instance of an encapsulated function.

Let's change the previous code a bit.

function someObj() {
    this.someMethod = someMethod;
    
    function someMethod() {
        alert('boo');
    }
}

o_obj = new someObj();

Now we've added the line this.someMethod = someMethod, which makes an individual and public reference to someMethod(). We might also make this neater by combining this.someMethod with the function declaration, as follows:

function someObj() {
    this.someMethod = function() {
        alert('boo');
    }
}

o_obj = new someObj();
o_obj.someMethod(); //alerts "boo"

If I execute the above script in a browser, I'll get an alert message with "boo" in it. Of course, what's good for the function is good for the variable, as shown in the following example.

function someObj() {
    this.publicVar = 'public';
    var privateVar = 'private';
    
    this.someMethod = function() {
        alert('boo');
    }
}

o_obj = new someObj();
alert(o_obj.publicVar); //alerts "public"
o_obj.publicVar = 'new';
alert(o_obj.publicVar); //alerts "new"
alert(o_obj.privateVar); //alerts nothing or an error, depending on the browser

Execute this in the browser, and you might get chills. Holy crap, we have public and private variables. You just have to remember that all references to a public variable within encapsulated functions must be preceeded by "this." or you'll end up accidentally creating a totally separate variable. And to bring it full circle, private methods are made possible like this...

function someObj() {
    this.publicVar = 'public';
    var privateVar = 'private';
    
    this.someMethod = function() {
        alert('boo');
        someOtherMethod();
    }
    
    // Private method. (Due to closure, this need not be declared before
    // someMethod although someMethod uses it.)
    var someOtherMethod = function() {
        alert('indirect reference');
    }
}

o_obj = new someObj();
o_obj.someOtherMethod(); //will throw an undefined function error
o_obj.someMethod(); //alerts "boo" followed by "indirect reference"

the above example shoud that function not given a "this." pointer is a defacto private method.

Here you will probably pause to realize that this particular black magic seems too good to be true. "Show me ye olde classical inheritance!" you cry. Here's where the limits to this sorcery are exposed. Classical inheritance doesn't come naturally to JavaScript. With a little coaxing you can get something equally useful, especially if you wish to build interrelated but independent libraries of encapsulated code following all of the other OOP rules we know and love. Consider the following:

function someObj() {
    this.o_otherobj;
    
    this.doOtherObj = function() {
        this.o_otherobj = new otherObj();
    }
}

function otherObj() {
    this.otherMethod = function() {
        alert('over the rainbow');
    }
}

o_obj = new someObj();
o_obj.doOtherObj();
o_obj.o_otherobj.otherMethod(); //alerts "over the rainbow"

This time, we have two independent and encapsulated functions, one essentially encapsulating another and providing a public interface. Those wondering if they can have a constructor function should note that in the above example that,

function someObj() {
    this.o_otherobj;
    
    this.doOtherObj = function() {
        this.o_otherobj = new otherObj();
    }
}

could just as easily have been,

function someObj() {
    this.o_otherobj = new otherObj();
}

and gotten the same result. Any code not encapsulated within that second-tier of functions is executed when the object is instantiated, mimicking constructor behavior.

Remember that standard variable scoping rules apply within encapsulated functions. Any variable declared in a second-tier function will become global to the whole class, so you have to be as careful with your namespace as you would be otherwise.

As a caveat, this method comes with more overhead than the typical usage of Javascript prototype to declare classes as each methods are duplicated across objects.

Alternate methods

For a more direct approach, you can copy the following into an .html file and play with it live in your browser.

<html>
<head>
<script type="text/javascript">
function jsObj() {
    this.m_public; //public variable
    this.o_griffins; //public variable
    
    this.doGriffins = doGriffins; // public method
    this.doSayItOutLoud = doSayItOutLoud; // public method
    this.getPrivateVariable = getPrivateVariable; // public method
    
    var m_private; // private variable
    
    alert('It\'s alive!'); //"constructor"
    
    function doSayItOutLoud(m_var_fp) { // this method is public because it has a "this." pointer
        this.m_public = m_var_fp;
        if (confirm(m_var_fp + ' is public knowledge. Do you wish to save it?')) {
            setPrivateVariable(m_var_fp);
        }
    }
    
    function doGriffins() {
        this.o_griffins = new familyObj();
    }
    
    function getPrivateVariable() { //this method is public because it has a "this." pointer
        alert('The private variable is ' + m_private);
    }
    
    function setPrivateVariable(m_var_fp) { //this method is private because it has no "this." pointer
        m_private = m_var_fp;
    }
}


function familyObj() {
    this.doMeg = doMeg;
    this.doPeter = doPeter;
    this.doStewie = doStewie;
    
    function doMeg(m_var_fp) {
        alert(m_var_fp + '. Is that what you want me to say?');
    }
    
    function doPeter() {
        alert('Bird, bird, bird, bird is the word!');
    }
    
    function doStewie() {
        alert('Thoughtless heathen programmer only gave me an alert().');
    }
}

var o_jsobj = new jsObj();
</script>
</head>
<body>
<div>
        For a good time, paste these snippets into your address bar!
    <ul>
        <li>javascript:o_jsobj.doSayItOutLoud('Yo!');</li>
        <li>javascript:alert(o_jsobj.m_public);</li>
        <li>javascript:alert(o_jsobj.m_public);</li>
        <li>(if you saved a variable) javascript:o_jsobj.getPrivateVariable();</li>
        <li>javascript:o_jsobj.getPrivateVariable();</li>
        <li>javascript:o_jsobj.doGriffins();</li>
        <li>javascript:o_jsobj.o_griffins.doMeg('Booger');</li>
        <li>javascript:o_jsobj.o_griffins.doPeter();</li>
        <li>javascript:o_jsobj.o_griffins.doStewie();</li>
    </ul>
</ul>
</div>
</body>
</html>
  • This page was last modified 22:41, 28 November 2008.
Edit this article
Reddit Digg
 
Subscribe now

Special Offer For Webmonkey Users

WIRED magazine:
The first word on how technology is changing our world.

Subscribe for just $10 a year