Monday, December 18, 2006

Javascript Objects: immediate and procedural, and an intro to pseudoclasses

An Object in Javascript is similar to that of other languages - it's essentially a way of structuring information and code in named subvariables of a single variable.

For example, the Math object has chilren like floor(), abs() and sin(), which should have obvious definitions by their names.

What most people don't realize, however, is that Javascript functions are also objects. So are Arrays. And Strings. In fact, anything that's not just a number is an Object.

Another thing they don't often notice is that they can make their own with relative ease. The simplest way is to use Javascript's immediate Object notation:
var myObject = {'myString':new String(), 'immediateString':'A little text', 'aNumber':2.71};

This creates an Object, named 'myObject', with three members: 'myString', 'immediateString', and 'aNumber'. Now, for example, to get a the 'myString' member, you can reference it in any of two ways:
myObject.myString="Lorem ipsum dolor sit";
alert(myObject['myString']);

Now, if you're pretty experienced as a programmer, you'll notice that the first is standard object reference notation, while the second is 'hash table' or 'associative array' notation - which exposes a nice little quirk of Javascript: Objects are little more than associative arrays. The fact that they can hold both scalar and complex variables is inherited from the ability of Javascript to handle both types in ANY variable.

Continuing on, we'll move to procedural notation:
var myObject = new Object();
myObject.myString = new String();
myObject.immediateString = 'A little text';
myObject.aNumber = 2.71;

This defines the same object as before, except does it by defining each variable one at a time. It's more to type, but more human-readable.

Lastly, we'll implement a pseudoclass. What we try to do with pseudoclasses is to implement features of C++ classes using Javascript Objects.

The below class is nothing more than a shell; a good starting point for building, for example, DHTML widgets.

function myClass() {
//Constructor code goes here
//Something I do if Timeouts are going to be involved:
this.instance=myClass.instances.push(this);
//which allows me to use setTimeout thusly:
this.timeout = setTimeout("myClass.instances["+this.instance+"].doSomething();", 5000);
//the below doesn't work right, as 'this' from the calling context of setTimeout is thw window object
this.timeout = setTimeout("this.doSomething();", 5000);
}
myClass.instances=new Array();
myClass.prototypes.doSomething = function () {
//This is the format for your basic non-static function
}

myClass.calculateSomething = function () {
//This is the format for static functions
}

myClass.eventHandlers = Object();
myClass.eventHandlers.documentLoad = function (e) {
/* I like using this paradigm for storing all my event handlers
Usually, before attaching a function to an element, I'll
set element.myClass.control to this, capture any relevant data from
the event object, then call a nonstatic function to deal with
the event.

Quick quirk: The best way I've found to get the source
element of an event:
*/
var src = this;
if (window.event) src=window.event.srcElement;
/* Please note that that is definately not 'one-size-fits-all' code;
testing for window.event is a way to determine if you're using
IE. you should find a way to use that as the only condition
to determine how you retrieve your event's information
*/
}


Note: If anyone knows how to gather the name of a non-anonymous function from within its own constructor, please tell me.

No comments: