You are here: Journal » JavaScript
   
Get syndicated feeds from our Journal!  Add to Technorati Favorites

Vertical Banner 1

   Minimize

Vertical Banner 2

   Minimize

Enter Title

   Minimize

The Dead Hand Journal

Journal

   Minimize
13

I'm in the process of writing an AJAX-based web application that—small surprise—requires a fair amount of processing on both the client and the server. My object model is complex, and on the server side I've simplified things by making heavy use of enumerated types. Ideally, I'd like to use a lighter-weight version of the same object model on the client side, but I immediately ran into a problem: JavaScript offers no native support for enumerated types!

I did some poking around, in the process learning a great deal about Object-Oriented Programming (OOP) in JavaScript. It turns out that OOP is fairly painless in JavaScript once you understand the techniques—Ray Djajadinata's article on MSDN is indispensable—but enumerated types are one thing he didn't really address, and nobody else has really managed to make them as painless as it seems they ought to be. All the tools are there, though, and with a little bit of thought, it turned out to be a remarkably easy problem to solve.

On the server side, declaring and instantiating an enumerated type looks something like this:

C#

namespace A.B

{

public enum Fruit

{

Apple,

Banana,

Cherry,

DavidHasselhoff 

}

}

 

A.B.Fruit myFruit = A.B.Fruit.Apple;

Let's make a couple of observations:

  • Namespaces matter. There is a strong argument to be made that one should never present code without embedding it in a namespace, in order to prevent name collisions. This is doubly true in JavaScript—where namespaces are still rare and collisions are thus more likely—and trebly true in a modular environment like DotNetNuke where a module developer can (by design!) have no idea what might be running one module over on the same page. Any robust enum implementation has got to support namespaces!
  • An enum declaration looks a lot like a class declaration, doesn't it? No constructor, but since every enum is really an int under the hood, why would you need one?
  • Let's take it one step farther: how is an enum really any different from an int? Answer: it has a bunch of static properties, one for each enumerated value!

Let's put these observations together and reconstitute our enum accordingly:

C#

namespace A.B

{

public class Fruit

{

// Static properties.

static public int Apple = 0;

static public int Banana = 1;

static public int Cherry = 2;

static public int DavidHasselhoff = 3; 

 

// Private data storage.

private int _Value;

 

// Public data interface.

public int Value

{

get { return _Value; }

set { _Value = value; }

}

}

}

 

// Since we went to the trouble to declare a class, we could
// initialize an instance by direct assignment... 

A.B.Fruit myFruit = A.B.Fruit.Apple;

 

// ... or via the constructor.

A.B.Fruit yourFruit = new A.B.Fruit(A.B.Fruit.DavidHasselhoff);

 

Pretty ugly, isn't it?

This becomes a useful exercise, though, when you match it up with the concepts Djajadinata presents in his article on JavaScript OOP, referenced above. Let's apply those concepts and translate the Fruit class into JavaScript:

JavaScript

// This is the outer namespace. We check if it exists;
// if it doesn't, we define it.

var A = A ? A : new Object();

 

// We do it again for the inner namespace.

A.B = A.B ? A.B : new Object();

 

// In Javascript, remember, a function is just an executable
// variable... and a class is its own constructor!

A.B.Fruit = function(_Value)

{

// Here's the public data interface. The private data
// storage is implicitly provided via closure.

this.getValue = function() { return _Value; };
this.setValue = function(val) { _Value = val; };

}

 

// Now we define the static properties that constitute
// the actual enumeration. In JavaScript OOP, a static 
// property is just a child object of the class!

A.B.Fruit.Apple = 0;

A.B.Fruit.Banana = 1;

A.B.Fruit.Cherry = 2;

A.B.Fruit.DavidHasselhoff = 3;

 

// That's it for the class declaration! Again, we can 
// initialize an instance by the JavaScript OOP equivalent
// of direct assignment...

var myFruit = new A.B.Fruit();

myFruit.setValue(A.B.Fruit.Apple);

 

// ... or via the constructor.

var yourFruit = new A.B.Fruit(A.B.Fruit.DavidHasselhoff);

Easy, right?

That's a joke. The instantiation is easy—it's only marginally more complex than the C# version—but the Javascript declaration is a nightmare! What we need is a helper function that can generate the appropriate namespace & class declaration behind the scenes. Then our "declaration" would be reduced to a function call, and really would be easy.

Here's one way to do it:

JavaScript

// This is the helper function. It creates the appropriate 
// namespace structure, generates the class constructor,
// and adds the appropriate static properties.
//
// The calling format is:
// 
// Enum(
//    "[ns_1.][ns_2.][...][ns_n.]TypeName",
//    "enum_1",
//    "enum_2",
//       .
//       .
//       .
//    "enum_m"
// );
//

function Enum()

{

// This is the class declaration (remember: in JavaScript, 
// a class is its own constructor!) that will ultimately
// be assigned into the appropriate namespace.

var e = function(_Value)

{

this.getValue = function() { return _Value; };

this.setValue = function(val) { _Value = val; };

}

 

// This segment defines the static parameters.

for (var i = 1; i < arguments.length; i++)

e[arguments]i[] = i - 1;

 

// This loop pulls the namespace hierarchy out of the first
// argument and creates it as required. Note that the root
// of the namespace—in fact, the parent object of all 
// global JavaScript variables—is the window object.

var path = arguments[0].split(".");

var parent = window;

 

while (path.length > 1)

{

child = path.shift();

if (parent[child] == undefined) parent[child] = new Object();

parent = parent[child];

}

 

// Having created the namespace hierarchy, we now emplace
// the class constructor.

parent[path] = e;

}

Now it's easy to declare and instantiate an arbitrary enumerated type! Here are the declaration and instantiation that correspond to the Fruit type:

JavaScript

// Here's the declaration...

Enum(

"A.B.Fruit",

"Apple",

"Banana",

"Cherry",

"DavidHasselhoff"

)

 

// And here are a couple of instantiations, just like before:

var myFruit = new A.B.Fruit();

myFruit.setValue(A.B.Fruit.Apple);

 

var yourFruit = new A.B.Fruit(A.B.Fruit.DavidHasselhoff);

To recap, what we've done is to declare a helper function, Enum(), that uses a simple syntax to generate an arbitrary enumerated type behind the scenes as a true object-oriented JavaScript class. Once declared, you can treat the resulting enum like any other JavaScript object class.

Post Rating

Comments

There are currently no comments, be the first to post one.

Post Comment

Only registered users may post comments.

Most Popular Articles

   Minimize
Cool Windows Resource Kit Utility: cleanspl.exe by Jason Williscroft (Tuesday, February 6, 2007)
v: 43760 | c: 5 Article Rating
They say things are big in Texas, but... by Robert Williscroft (Wednesday, March 7, 2007)
v: 27459 | c: 1 Article Rating
Sweet vindication – It really is climate cooling! by Robert Williscroft (Thursday, January 3, 2008)
v: 22233 | c: 11 Article Rating
E-Bomb: The Ultimate Terrorist Weapon by Robert Williscroft (Thursday, December 28, 2006)
v: 20833 | c: 5 Article Rating
Global Warming Deniers – Part 1 – Statistics needed by Robert Williscroft (Wednesday, February 7, 2007)
v: 16725 | c: 9 Article Rating

CLA

   Minimize
The Chicken Little Agenda: Debunking "Experts’" Lies

Block 1

   Minimize

Block 2

   Minimize