以下内容是否会使对象满足枚举在JavaScript中的所有特性?类似于:

my.namespace.ColorEnum = {
  RED : 0,
  GREEN : 1,
  BLUE : 2
}

// later on

if(currentColor == my.namespace.ColorEnum.RED) {
  // whatever
}

还是有其他方法可以做到这一点?


当前回答

在大多数现代浏览器中,有一种符号基元数据类型,可用于创建枚举。它将确保枚举的类型安全,因为JavaScript保证每个符号值都是唯一的,即symbol()!=符号()。例如:

const COLOR = Object.freeze({RED: Symbol(), BLUE: Symbol()});

为了简化调试,可以向枚举值添加描述:

const COLOR = Object.freeze({RED: Symbol("RED"), BLUE: Symbol("BLUE")});

Plunker演示

在GitHub上,您可以找到一个包装器,它简化了初始化枚举所需的代码:

const color = new Enum("RED", "BLUE")

color.RED.toString() // Symbol(RED)
color.getName(color.RED) // RED
color.size // 2
color.values() // Symbol(RED), Symbol(BLUE)
color.toString() // RED,BLUE

其他回答

var DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });

您不需要指定id,只需使用空对象来比较枚举即可。

if (incommingEnum === DaysEnum.monday) //incommingEnum is monday

EDIT:如果要序列化对象(例如JSON),将再次输入id。

(摘自加布里埃尔·利亚马斯评论)(根据Stijn de Witt的评论进行编辑)

更新

我认为我下面的答案不再是用JavaScript编写枚举的最佳方法。有关更多详细信息,请参阅我的博客文章:JavaScript中的枚举。


已经可以提醒名称:

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);
   }
}

或者,您可以创建值对象,这样您就可以吃蛋糕了:

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 + ": " + currentSize.name);
}

在JavaScript中,因为它是一种动态语言,所以以后甚至可以向集合中添加枚举值:

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

记住,枚举的字段(本例中的值、名称和代码)不需要用于身份检查,只是为了方便。此外,大小属性本身的名称不需要硬编码,也可以动态设置。因此,假设您只知道新枚举值的名称,您仍然可以毫无问题地添加它:

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

当然,这意味着无法再进行某些假设(例如,该值表示大小的正确顺序)。

记住,在JavaScript中,对象就像一个映射或哈希表。一组名称值对。你可以在事先不了解它们的情况下循环浏览它们或以其他方式操纵它们。

实例

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.        
  }
} 

顺便说一句,如果你对名称空间感兴趣,你可能想看看我为JavaScript提供的简单但强大的名称空间和依赖关系管理的解决方案:Packages JS

我刚刚发布了一个NPM包gen_enum,它允许您在Javascript中快速创建enum数据结构:

var genEnum = require('gen_enum');

var AppMode = genEnum('SIGN_UP, LOG_IN, FORGOT_PASSWORD');
var curMode = AppMode.LOG_IN;
console.log(curMode.isLogIn()); // output true 
console.log(curMode.isSignUp()); // output false 
console.log(curMode.isForgotPassword()); // output false 

这个小工具的一个优点是在现代环境中(包括nodejs和IE9+浏览器),返回的Enum对象是不可变的。

有关更多信息,请结账https://github.com/greenlaw110/enumjs

更新

我淘汰了gen_enum包,并将该函数合并到constjs包中,该包提供了更多功能,包括不可变对象、JSON字符串反序列化、字符串常量和位图生成等。签出https://www.npmjs.com/package/constjs了解更多信息

要从gen_enum升级到constjs,只需更改语句

var genEnum = require('gen_enum');

to

var genEnum = require('constjs').enum;

这不是一个很好的答案,但我个人认为这很好

话虽如此,因为值是什么并不重要(您使用了0、1、2),所以我会使用一个有意义的字符串,以防您想要输出当前值。

更新05.11.2020:修改为包含静态字段和方法,以更接近地复制“true”枚举行为。

是否有人尝试过使用包含私有字段和“get”访问器的类执行此操作?我意识到私有类字段目前仍处于实验阶段,但它似乎可以用于创建具有不可变字段/财产的类。浏览器支持也不错。唯一不支持它的“主要”浏览器是Firefox(我相信他们很快就会支持)和IE(谁在乎)。

免责声明:我不是一个开发者。我只是在寻找这个问题的答案,并开始思考我有时如何通过创建带有私有字段和受限属性访问器的类来在C#中创建“增强”枚举。

样本类别

class Sizes {
    // Private Fields
    static #_SMALL = 0;
    static #_MEDIUM = 1;
    static #_LARGE = 2;

    // Accessors for "get" functions only (no "set" functions)
    static get SMALL() { return this.#_SMALL; }
    static get MEDIUM() { return this.#_MEDIUM; }
    static get LARGE() { return this.#_LARGE; }
}

现在您应该可以直接调用enums。

Sizes.SMALL; // 0
Sizes.MEDIUM; // 1
Sizes.LARGE; // 2

使用私有字段和有限访问器的组合意味着枚举值得到了很好的保护。

Sizes.SMALL = 10 // Sizes.SMALL is still 0
Sizes._SMALL = 10 // Sizes.SMALL is still 0
Sizes.#_SMALL = 10 // Sizes.SMALL is still 0