Zettabyte Storage

Tuesday, January 16, 2007

Making Javascript Useful: Part 1, Simple Classes

Before I get into this blog, I should mention that I am not the first person to write what is essentially the first three articles of this series. It's also probably not the best discussion of the topic. When I got started seriously using Javascript, much of this information did not exist (at least on the web where I looked). After writing Part 0 and most of Part 1 (this post), I realized that the internet is both (1) not static and (2) tends towards ever greater knowledge. Sure enough, when I looked again, there was much more information than was available only a year ago. Now that I no longer need the information, it is more plentifully available than the grains of sand on a beach - it prickles similarly too.

From my peremptory scan of Google's top picks, one of the best places to go looking for advanced Javascript is: http://javascript.crockford.com - The article "JavaScript: The World's Most Misunderstood Programming Language" even has a section "Lisp in C's Clothing". Not only am I late to the party, but Mr. Crockford has much catchier wording. All is not lost, however; there is as yet very little (good) information about polymorphism out there. Besides, this is all really just introductory material for the real topic of this series: making javascript and the web a real programming and distribution environment - this goes well beyond OOP and should provide me with interesting things to say well into the future.

Sadly, I couldn't find the article that originally pointed out how to do some very basic OOP things with Javascript. So props go to whoever the mystery hacker happened to be, even if I can't remember their name.

And now on to our main feature:

What it all comes down to is playing up to your talents. When you get down to it, Javascript has a very odd set of talents.

The things we want to do with Javascript are essentially the things we want to do with any other programming language: build tools powerful enough that doing the really hard work can be made entirely someone else's problem. What are the tools that javascript* comes with "out of the box"?

  1. generic Functions and Objects and the things we like doing with them (closures, hashing, et.al.)
  2. a plethora of high and low level syntax (operators, if/then, while, function, et.al.)
  3. free and easy memory management (when and if it works at all)
  4. a powerful string library
There are other things that come to mind (and probably some important ones that don't), but these are the big 4. This is actually a much bigger set of functionality than most environments give us. For instance, C only gives us 2**. Everyone that builds a significantly large piece of code in C ends up reimplementing 1, 3, and 4 out of hand; Apache has it's pools and buckets, gtk has GObject, etc.

The one thing that Javascript doesn't give us (and, ironically, the BigThing for its namesake Java) is OOP. Of course we have the "Object" object, but what we really want is a class template, instances, public and private data, interfaces, super/subclassing, etc.

Without further ado, let's define a class:


function MyClass()
{
    <blah>
}


You are probably wondering why our "class" is defined with the 'function' keyword. Remember that the 'function' keyword is just a shortcut for declaring something like Function( "" ). Since the Function object is just another 'Object', we can tack properties (hash-table keys) onto it willy-nilly; if those properties happen to be other functions, so much the better. Specifically, we are going to use the 'this' keyword from inside the function to tack properties on the function object that represents the class. Thus, like with a real class, our "class" will be a wrapper for function definitions, like so:

Defining public functions:


function MyClass()
{
    this.MyPublicMethod = function()
    {
    };
}


The problem here is the value of 'this'. I've already mentioned that the 'this' refers to the function object that we are creating, but it is not clear why that should be the case. If you just call the MyClass function (it is really a function after all), you would expect 'this' to refer to nothing, since MyClass resides in the top-level containing block which has no 'this', since 'this' always refers to an Object(ish). Enter the 'new' keyword. The 'new' keyword copies the Function object created by 'function MyClass' and calls the new MyClass Function with 'this' set to the new Function object. The 'new' keyword is what creates the class's instance - a Function object.

We instantiate the class like so:


var my_class_instance = new MyClass();
/*
typeof my_class_instance == Function
typeof my_class_instance[ 'MyPublicMethod' ] == Function
*/


Note: in the definition of MyClass there is a semicolon after the definition of MyPublicMethod. Consider this a litmus test: if you understand what we're doing with the Function object, it should be obvious why this is needed. If you don't understand why there is a semicolon here, you should think about it until you do: it is important.***

Defining Public Data:


function MyClass()
{
    this._myPublicData = 0;
}


Since you understand that 'this' is just tagging keys into a Function object, it should be pretty obvious that we can do the same thing with other types of data as well.

Private functions and variables are a little tricker. First, let's review the concept of the "closure". I think I must have accidentally slept through the lecture where this was defined formally, but it's actually really easy. Just go read Wikipedia's article on it if you are not familiar. (http://en.wikipedia.org/wiki/Closure_%28computer_science%29) One of the things that I purposely failed to mention earlier about the 'new' operator is that it also forms a "closure" with the function. Essentially, what this boils down to is that the variables you use in the function are, simultaneously, kept around by the Function object with their current values, and are available to any functions you define within the class 'function'. Incidentally, they are not available to anyone who is not declared inside the function.

Defining Private Stuff:


function MyClass()
{
    var _myPrivateData = 0;
    var _myPrivateFunction = function()
    {
        _myPrivateData++;
    };
}

var my_instance = new MyClass();
/* window.alert( my_instance._myPrivateData ); // javascript dies */
/* window.alert( my_instance._myPrivateFunction() ); // javascript dies */


These examples should give us everything that we need to know to define, instance, and use basic (non polymorphic) objects. In my next article, I will finish up with the basics with an article implementing polymorphism in javascript.

* - I don't care about your browser's DOM tree and its cute little HTML renderer - we are talking about core ecmascript here

** - Keep in mind that I said a "powerful" string library; the cstdlib hardly counts.

*** - You are creating a Function object with the 'function' keyword and assigning it to a property in the class's Function object. The semicolon goes after the property assignment, even if it is a function you are assigning. Actually, you don't really _need_ a semicolon here: a conforming Javascript interpreter will be able to deduce the property ending correctly. Of course, that notion presuposes that there exists some conforming Javascript interpreter. In general, if a semicolon can go there, it should go there, because it will almost always make the interpreter's job easier.

0 Comments:

Post a Comment

<< Home