Grauw’s blog

JavaScript enumeration pattern

September 25th, 2012

Although often better handled with subclasses and polymorphism, enumerations can be a convenient light-weight way to indicate some kind of state or non-boolean flag.

When one makes an enumeration in JavaScript, it is typically an old-fashioned list of constants with integer number values:

var MyEnum = {};
MyEnum.FIRST = 0;
MyEnum.SECOND = 1;
MyEnum.THIRD = 2;

A downside of this approach is that it is not type-safe; these values can not be distinguished from any other number. Additionally, it is possible to cheat by hardcoding a value somewhere, which makes code less readable and refactoring a lot harder.

There is a better way however:

function MyEnum() {}
MyEnum.FIRST = new MyEnum();
MyEnum.SECOND = new MyEnum();
MyEnum.THIRD = new MyEnum();

When one of these is passed to a method its type can be checked using instanceof or a function like checkTypes(). And because these are unique object references they are impossible to specify without using the constants.

Additionally, because this effectively defines a class it comes with a lot of power. E.g. you can pass meta-data and handy functions:

function MyEnum(name) { this._name = name; }
MyEnum.prototype.toString = function() { return this._name; };

MyEnum.FIRST = new MyEnum("FIRST");
MyEnum.SECOND = new MyEnum("SECOND");
MyEnum.THIRD = new MyEnum("THIRD");

Finally, as you discover you want to move more and more functionality onto this enumeration, it is easy to upgrade the enumeration to a full-fledged set of subclasses:

function First() {
    MyEnum.call(this, "FIRST");
}
extend(MyEnum, First);

function Second() {
    MyEnum.call(this, "SECOND");
}
extend(MyEnum, Second);

function Third() {
    MyEnum.call(this, "THIRD");
}
extend(MyEnum, Third);

Grauw

Comments

None.