You are hereBlogs / rahul's blog / Enums in Javascript - Part 2

Enums in Javascript - Part 2


rahul's picture

By rahul - Posted on 03 February 2010

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:

 

EnumBase = function(val, display) {
    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.';
    }
}

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.

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.

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);

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:
    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);
    
    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).

Post new comment

The content of this field is kept private and will not be shown publicly.

Mollom CAPTCHA (play audio CAPTCHA)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.