This post describes a JavaScript implementation of
enums, enumerations of symbols. The idea originally comes from Allen Wirfs-Brock, via a
thread on the es-discuss mailing list.
Using an enum
var color = new enums.Enum("red", "green", "blue");
function isGreen(c) {
return c === color.green;
}
color.green is an object (an instance of
Symbol) and
a === b is only true if
a and
b are the same object, so the above works out nicely. Interaction:
> isGreen(color.red)
false
> isGreen(color.green)
true
The cool thing is that switch works, too:
function translate(c) {
switch(c) {
case color.red:
return "rot";
case color.green:
return "grün";
case color.blue:
return "blau";
}
}
Interaction:
> translate(color.red)
'rot'
You can also give enum symbols custom properties:
var color = new enums.Enum({
red: { de: "rot" },
green: { de: "grün" },
blue: { de: "blau" },
});
Then
translate() becomes simpler:
function translate(c) {
return c.de;
}
Lastly, enum symbols can also be converted to string:
> console.log("The sky is "+color.blue);
The sky is |blue|
> console.log("The sky is "+color.blue.name);
The sky is blue
Isn’t there an easier way? You might think that the following is simpler than an enum:
var color2 = {
red: "red",
green: "green",
blue: "blue",
}
However, it is a problem of type safety: Enum symbols are not equal to anything but themselves. The properties of
color2 do not exhibit this behavior:
> color2.red === "red"
true
> color.red === "red"
false
The implementation
You can download the
enums project on GitHub. It consists of two constructors:
- Symbol implements the symbols that an enum holds. Symbols are immutable.
- Enum implements enums. Each enum is an object that maps symbol names to symbol instances. Enums are immutable.
There are several measures to make instances of
Symbol as immutable as possible:
- The prototype of symbols is frozen (immutable).
- The prototype of symbols has no prototype. Normally, Symbol.prototype would have the prototype Object.prototype (which comes with several standard methods etc.). But Object.prototype is mutable which we want to avoid.
- Instances of Symbol are frozen.
Note: Without
Object.prototype in the prototype chain, we need to provide a
toString() method. Otherwise symbols cannot be converted to string, e.g. to display them on a command line.