Enums in Javascript with ES6

2019-01-21 07:11发布

I'm rebuilding an old Java project in Javascript, and realized that there's no good way to do enums in JS.

The best I can come up with is:

const Colors = {
    RED: Symbol("red"),
    BLUE: Symbol("blue"),
    GREEN: Symbol("green")
};
Object.freeze(Colors);

The const keeps Colors from being reassigned, and freezing it prevents mutating the keys and values. I'm using Symbols so that Colors.RED is not equal to 0, or anything else besides itself.

Is there a problem with this formulation? Is there a better way?


(I know this question is a bit of a repeat, but all the previous Q/As are quite old, and ES6 gives us some new capabilities.)


EDIT:

Another solution, which deals with the serialization problem, but I believe still has realm issues:

const enumValue = (name) => Object.freeze({toString: () => name});

const Colors = Object.freeze({
    RED: enumValue("Colors.RED"),
    BLUE: enumValue("Colors.BLUE"),
    GREEN: enumValue("Colors.GREEN")
});

By using object references as the values, you get the same collision-avoidance as Symbols.

10条回答
劳资没心,怎么记你
2楼-- · 2019-01-21 07:45

Also check Enumify, a very good and well featured library for ES6 enums.

Hope this will help somebody.

Best regards,

Emmanuel

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-01-21 07:45

You could use ES6 Map

const colors = new Map([
  ['RED', 'red'],
  ['BLUE', 'blue'],
  ['GREEN', 'green']
]);

console.log(colors.get('RED'));
查看更多
唯我独甜
4楼-- · 2019-01-21 07:52

Check how TypeScript does it. Basically they do the following:

const MAP = {};

MAP[MAP[1] = 'A'] = 1;
MAP[MAP[2] = 'B'] = 2;

MAP['A'] // 1
MAP[1] // A

Use symbols, freeze object, whatever you want.

查看更多
Animai°情兽
5楼-- · 2019-01-21 07:56

If you don't need pure ES6 and can use Typescript, it has a nice enum:

https://www.typescriptlang.org/docs/handbook/enums.html

查看更多
我只想做你的唯一
6楼-- · 2019-01-21 07:57

As mentioned above, you could also write a makeEnum() helper function:

function makeEnum(arr){
    let obj = {};
    for (let val of arr){
        obj[val] = Symbol(val);
    }
    return Object.freeze(obj);
}

Use it like this:

const Colors = makeEnum(["red","green","blue"]);
let startColor = Colors.red; 
console.log(startColor); // Symbol(red)

if(startColor == Colors.red){
    console.log("Do red things");
}else{
    console.log("Do non-red things");
}
查看更多
Summer. ? 凉城
7楼-- · 2019-01-21 07:58

Whilst using Symbol as the enum value works fine for simple use cases, it can be handy to give properties to enums. This can be done by using an Object as the enum value containing the properties.

For example we can give each of the Colors a name and hex value:

/**
 * Enum for common colors.
 * @readonly
 * @enum {{name: string, hex: string}}
 */
const Colors = Object.freeze({
  RED:   { name: "red", hex: "#f00" },
  BLUE:  { name: "blue", hex: "#00f" },
  GREEN: { name: "green", hex: "#0f0" }
});

Including properties in the enum avoids having to write switch statements (and possibly forgetting new cases to the switch statements when an enum is extended). The example also shows the enum properties and types documented with the JSDoc enum annotation.

Equality works as expected with Colors.RED === Colors.RED being true, and Colors.RED === Colors.BLUE being false.

查看更多
登录 后发表回答