How can I guarantee that my enums definition doesn't change in JavaScript?

ID : 337

viewed : 94

Tags : javascriptjavascript

Top 5 Answer for How can I guarantee that my enums definition doesn't change in JavaScript?

vote vote


Since 1.8.5 it's possible to seal and freeze the object, so define the above as:

const DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...}) 


const DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...} Object.freeze(DaysEnum) 

and voila! JS enums.

However, this doesn't prevent you from assigning an undesired value to a variable, which is often the main goal of enums:

let day = DaysEnum.tuesday day = 298832342 // goes through without any errors 

One way to ensure a stronger degree of type safety (with enums or otherwise) is to use a tool like TypeScript or Flow.

Quotes aren't needed but I kept them for consistency.

vote vote


This isn't much of an answer, but I'd say that works just fine, personally

Having said that, since it doesn't matter what the values are (you've used 0, 1, 2), I'd use a meaningful string in case you ever wanted to output the current value.

vote vote



Thanks for all the upvotes everyone, but I don't think my answer below is the best way to write enums in JavaScript anymore. See my blog post for more details: Enums in JavaScript.

Alerting the name is already possible:

if (currentColor == my.namespace.ColorEnum.RED) {    // alert name of currentColor (RED: 0)    var col = my.namespace.ColorEnum;    for (var name in col) {      if (col[name] == col.RED)        alert(name);    } } 

Alternatively, you could make the values objects, so you can have the cake and eat it too:

var SIZE = {   SMALL : {value: 0, name: "Small", code: "S"},    MEDIUM: {value: 1, name: "Medium", code: "M"},    LARGE : {value: 2, name: "Large", code: "L"} };  var currentSize = SIZE.MEDIUM; if (currentSize == SIZE.MEDIUM) {   // this alerts: "1: Medium"   alert(currentSize.value + ": " +; } 

In JavaScript, as it is a dynamic language, it is even possible to add enum values to the set later:

// Add EXTRALARGE size SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"}; 

Remember, the fields of the enum (value, name and code in this example) are not needed for the identity check and are only there for convenience. Also the name of the size property itself does not need to be hard coded, but can also be set dynamically. So supposing you only know the name for your new enum value, you can still add it without problems:

// Add 'Extra Large' size, only knowing it's name var name = "Extra Large"; SIZE[name] = {value: -1, name: name, code: "?"}; 

Of course this means that some assumptions can no longer be made (that value represents the correct order for the size for example).

Remember, in JavaScript an object is just like a map or hash table. A set of name-value pairs. You can loop through them or otherwise manipulate them without knowing much about them in advance.


for (var sz in SIZE) {   // sz will be the names of the objects in SIZE, so   // 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'   var size = SIZE[sz]; // Get the object mapped to the name in sz   for (var prop in size) {     // Get all the properties of the size object, iterates over     // 'value', 'name' and 'code'. You can inspect everything this way.           } }  

And by the way, if you are interested in namespaces, you may want to have a look at my solution for simple but powerful namespace and dependency management for JavaScript: Packages JS

vote vote


Bottom line: You can't.

You can fake it, but you won't get type safety. Typically this is done by creating a simple dictionary of string values mapped to integer values. For example:

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}  Document.Write("Enumerant: " + DaysEnum.tuesday); 

The problem with this approach? You can accidentally redefine your enumerant, or accidentally have duplicate enumerant values. For example:

DaysEnum.monday = 4; // whoops, monday is now thursday, too 


What about Artur Czajka's Object.freeze? Wouldn't that work to prevent you from setting monday to thursday? – Fry Quad

Absolutely, Object.freeze would totally fix the problem I complained about. I would like to remind everyone that when I wrote the above, Object.freeze didn't really exist.

Now.... now it opens up some very interesting possibilities.

Edit 2
Here's a very good library for creating enums.

While it probably doesn't fit every valid use of enums, it goes a very long way.

vote vote


Here's what we all want:

function Enum(constantsList) {     for (var i in constantsList) {         this[constantsList[i]] = i;     } } 

Now you can create your enums:

var YesNo = new Enum(['NO', 'YES']); var Color = new Enum(['RED', 'GREEN', 'BLUE']); 

By doing this, constants can be acessed in the usual way (YesNo.YES, Color.GREEN) and they get a sequential int value (NO = 0, YES = 1; RED = 0, GREEN = 1, BLUE = 2).

You can also add methods, by using Enum.prototype:

Enum.prototype.values = function() {     return this.allValues;     /* for the above to work, you'd need to do             this.allValues = constantsList at the constructor */ }; 

Edit - small improvement - now with varargs: (unfortunately it doesn't work properly on IE :S... should stick with previous version then)

function Enum() {     for (var i in arguments) {         this[arguments[i]] = i;     } }  var YesNo = new Enum('NO', 'YES'); var Color = new Enum('RED', 'GREEN', 'BLUE'); 

Top 3 video Explaining How can I guarantee that my enums definition doesn't change in JavaScript?