带es6的javascript中的枚举

Enums in Javascript with ES6

我在JavaScript中重建一个旧的Java项目,并意识到在JS中没有好的方法来执行枚举。

我能想到的最好办法是:

1
2
3
4
5
6
const Colors = {
    RED: Symbol("red"),
    BLUE: Symbol("blue"),
    GREEN: Symbol("green")
};
Object.freeze(Colors);

const防止Colors被重新分配,冻结它可以防止键和值发生变化。我使用符号是为了使Colors.RED不等于0,或者其他任何东西。

这个配方有问题吗?有更好的方法吗?

(我知道这个问题有点重复,但是之前的Q/A都很旧,ES6为我们提供了一些新功能。)

编辑:

另一个解决方案是处理序列化问题,但我认为仍然存在领域问题:

1
2
3
4
5
6
7
const enumValue = (name) => Object.freeze({toString: () => name});

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

通过使用对象引用作为值,可以获得与符号相同的碰撞避免。


Is there a problem with this formulation?

我什么也没看到。

Is there a better way?

我将把这两个语句折叠成一个:

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

如果您不喜欢样板文件,比如重复的Symbol调用,那么当然您也可以编写一个助手函数makeEnum,它从一系列名称中创建相同的内容。


虽然使用Symbol作为枚举值对于简单的用例来说很好,但是可以方便地为枚举提供属性。这可以通过使用Object作为包含属性的枚举值来实现。

例如,我们可以为每个Colors指定一个名称和十六进制值:

1
2
3
4
5
6
7
8
9
10
/**
 * 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" }
});

在枚举中包含属性可以避免编写switch语句(并且在扩展枚举时可能会忘记switch语句的新情况)。该示例还显示了jsdoc枚举注释中记录的枚举属性和类型。

平等工作与预期一致,Colors.RED === Colors.REDtrueColors.RED === Colors.BLUEfalse


检查typescript的工作方式。基本上,它们执行以下操作:

1
2
3
4
5
6
7
const MAP = {};

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

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

使用符号,冻结对象,无论你想要什么。


如前所述,还可以编写makeEnum()助手函数:

1
2
3
4
5
6
7
function makeEnum(arr){
    let obj = {};
    for (let val of arr){
        obj[val] = Symbol(val);
    }
    return Object.freeze(obj);
}

这样使用:

1
2
3
4
5
6
7
8
9
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");
}


您可以检查Enumify,这是一个非常好的ES6 Enums功能良好的库。


这是我个人的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ColorType {
    static get RED () {
        return"red";
    }

    static get GREEN () {
        return"green";
    }

    static get BLUE () {
        return"blue";
    }
}

// Use case.
const color = Color.create(ColorType.RED);


如果您不需要纯ES6并且可以使用typescript,那么它有一个很好的enum

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


也许这个解决方案?:)

1
2
3
4
5
6
7
8
9
function createEnum (array) {
  return Object.freeze(array
    .reduce((obj, item) => {
      if (typeof item === 'string') {
        obj[item] = Symbol(item)
      }
      return obj
    }, {}))
}

您还可以使用ES6枚举包(https://www.npmjs.com/package/es6 enum)。它很容易使用。见下面的例子


你可以用ES6地图

1
2
3
4
5
6
7
const colors = new Map([
  ['RED', 'red'],
  ['BLUE', 'blue'],
  ['GREEN', 'green']
]);

console.log(colors.get('RED'));