Question

So, I was inspired by this question ( Enums in JavaScript? ) to get to work on a library insert for JavaScript to enable unmodifiable Enumerations. I have a decently working method defined already, but I'd like to flesh it out more.

This concept makes use of Object.defineProperty (Documentation: Here)

My current definition allows for :

var obj1 = {}, obj2 = {}, obj3 = {};
// Straight declaration (normal)
obj1.Enum('RED','BLUE','GREEN');
obj1.RED    // == 0
obj1.BLUE   // == 1
obj1.GREEN  // == 2
// Buffer (padding) usage
obj2.Enum('RED','BLUE',null,undefined,'','GREEN');
obj2.RED    // == 0
obj2.BLUE   // == 1
obj2.GREEN  // == 5
// Direct offset and case-correction
obj3.Enum('RED','BLUE',10,'gReEn','burnt orange');
obj3.RED           // == 0
obj3.BLUE          // == 1
obj3.GREEN         // == 11
obj3.BURNT_ORANGE  // == 12

What I have so far:

var odp=Object.defineProperty;
odp(Object.prototype,'Enum', {
    value: function() {
        var ignore=[undefined,null,''], n=0, args=arguments;
        for(var i in args) {
            if(ignore.indexOf(args[i])<0) {
                if( typeof args[i]=="number") {
                    n=parseInt(args[i]);
                } else {
                    try {
                        odp(this,String(args[i]).toUpperCase().replace(" ","_"), {
                            value:parseInt(n),enumerable:true
                        });
                    } catch(e) {
                        console.warn(e.message);
                        n--;
                    }
                }
            }
            n++;
        }
        return this;
    }
});

2 things I'd like to add to this are:

  1. Older browser support: So, redefining Object.defineProperty where it's not defined. (I don't currently have access to the older browsers to test possible re-definitions)
  2. Any considerations I may have missed it the Enum definition.

jsFiddle :

Note: The reason I have odp=Object.defineProperty and args=arguments is that I run my JavaScript through a closure compiler before inserting it into my pages, doing this assists with compression. (for those that may be wondering)

Was it helpful?

Solution

Older browser support: So, redefining Object.defineProperty where it's not defined.

You can't do that with your current approach, because your current approach extends Object.prototype. Extending Object.prototype should very, very rarely be done if you have ES5 support, but it must never be done without it, because without Object.defineProperty, you have no way to create a non-enumerable property. Adding enumerable properties to Object.property will break all of your for-in loops.

There's no reason for Enum to be on the prototype anyway, though, just put it on Object (or your own library object) and pass the object to be enum-ified into it.

Any considerations I may have missed it the Enum definition.

It seems to me that this offers little on top of:

var obj = Object.freeze({
    "RED":   0,
    "GREEN": 1,
    "BLUE":  2
});

You might wrap that up into a function that will work, without freezing the object, in pre-ES5 environments, e.g.:

function createEnum(spec) {
    if (Object.freeze) {
        spec = Object.freeze(spec);
    }
    return spec;
}

You can enhance that, of course, if you want the automatic values, e.g:

function createEnum(spec) {
    var obj = {}, n;
    if (Object.prototype.toString.call(spec) === "[object Array]") { // No isArray pre ES5
        for (n = 0; n < spec.length; ++n) {
            if (spec[n] != null) { // checks for null or undefined
                obj[spec[n]] = n;
            }
        }
    }
    else {
        for (n in spec) {
            if (spec.hasOwnProperty(n)) {
                obj[n] = spec[n];
            }
        }
    }
    if (Object.freeze) {
        obj = Object.freeze(obj);
    }
    return obj;
}

You could put that on Object (not Object.prototype), if you liked.


Below you've said that you don't want to use freeze because it makes the object non-extensible. Fair enough, wanting to add further enum values later. The above is easily adapted to doing that, using Object.defineProperty if present and falling back on just assigning the property if not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top