I blogged about this topic earlier also here. That blog post presents an approach to create enums (enumerations) in javascript, exactly like those available in .NET or Java.

The later portion of that blog post mentions that the approach presented is extensible, and we can move the parse() and toString() methods to a base class easily. I knew I would myself need to do this some day (create a base javascript class for enums), but never expected it to be this much soon.

I am currently working on a Web app, that maintains all sorts of flags on the client side, and I need to convert the flag’s integral value to string & vice versa. Perfect, scenario for enums most would agree. Now, I did not want to replicate the parse() and toString() methods for each enum.

So I decided to create a base javascript class for enums. And it was more challenging than I thought. Without wasting any more of time, here’s the base class:

 

{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }EnumBase = function(val, display) {
if (Ext.isEmpty(this.constructor.items)) {
this.constructor.items = [];
}
this.constructor.items.push(this);

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

this.toJSON = function() {
return (val);
},

this.toString = function(throwIfNotFound) {
if (!Ext.isEmpty(display)) {
return (display);
} else {
var key = MB.EnumBase.getKeyByValue(this.constructor, this.getValue());
if (!Ext.isEmpty(key))
return (key);
else if (throwIfNotFound)
throw val + ‘ is not a valid value.’;
else
return (this.val);
}
}
}

EnumBase.getKeyByValue = function(c, val) {
for (key in c) {
var obj = c[key];
if (obj instanceof c && obj.getValue() == val) {
return (key);
}
}
return (null);
}

EnumBase.parse = function(c, str) {
var val = c[str];
if (val != undefined) {
return (val);
} else {
var key = EnumBase.getKeyByValue(c, str);
if (!Ext.isEmpty(key))
return (c[key]);
else
throw str + ‘ cannot be parsed.’;
}
}{/syntaxhighlighter}

It has 3 regular methods, getValue(), toString() and toJSON(), where the first returns the integral value of the enum variable, the second returns its string representation while the third is used for serialization of enum values to JSON.
It also has a static items property which holds the enum objects created for a prticular enumeration.

The 2 static methods on EnumBase constitute its private API to be used by itself, and derived enums.

Now, here’s an example of an enum derived from it.

{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }ChangeAction = Ext.extend(EnumBase, {});

ChangeAction.parse = function(str) {
return (EnumBase.parse(ChangeAction, str));
}

ChangeAction.None = new ChangeAction(0);
ChangeAction.Insert = new ChangeAction(1);
ChangeAction.Delete = new ChangeAction(2);
ChangeAction.Update = new ChangeAction(3);{/syntaxhighlighter}

Each derived enum would need to provide the single-line parse method again due to obvious static method limitations in overriding. I have used ExtJs to extend ChangeAction from EnumBase. If you do not use ExtJs, it should not be difficult doing it manually.

The last 4 lines add the flags for the ChangeAction enum. You can add as many flags as you like, and you can also assign the same integral value to multiple flags.

Finally, here are a few samples of how you can use these enums:

 

var v1 = ChangeAction.None;
alert(v1.getValue());

var v2 = ChangeAction.parse('Insert');
alert(v2.toString());

var v4 = ChangeAction.parse(3);
alert(v4.toString());

 

You would agree, we have succeeded in emulating complete .net or java like enums in javascript.

UPDATE:

  • (Mar 1, 2010) – Added to JSON() support, and improved toString() support.
    I have overriden  ExtJs’s Ext.util.JSON.encode method to enable objects to provide toJSON() method, which is used while serializing an object to JSON using the encode() method.
    The enum’s integral value is used for serialization.
  • Enhanced toString() to support custom display values. Therefore, you can now use expressions like the following:
    {syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }PaymentMode = Ext.extend(MB.EnumBase, {});

    PaymentMode.parse = function(str) {
    return (MB.EnumBase.parse(PaymentMode, str));
    }

    PaymentMode.Cash = new PaymentMode(0, ‘CASH / CHEQUE’);
    PaymentMode.CreditCard = new PaymentMode(1, ‘CREDIT CARD’);
    PaymentMode.InHouseCc = new PaymentMode(2, ‘IN HOUSE CC’);
    PaymentMode.Atm = new PaymentMode(3);
    PaymentMode.Receivable = new PaymentMode(4);
    {/syntaxhighlighter}This allows you to specify a custom string for display purposes. Notice the custom display string is optional, and if not specified, the enum value name itself is used for display. Also, the parse() method would parse only the integer and enum name corresponding into the enum object, but not the custom display string (if specified).

  • (Mar 25, 2010) – Added the static items property to EnumBase. This property contains all Enum objects created for a particular enum derived from EnumBase, and thus allows you to iterate the Enum objects in javascript like: {syntaxhighlighter brush: as3;fontsize: 100; first-line: 1; }for (key in ChangeAction.items) {
    var e = ChangeAction.items[key];
    //Process e here (the current enum object)
    }{/syntaxhighlighter}