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

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

// later on

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

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


当前回答

阅读了所有的答案,没有找到任何非冗长和干燥的解决方案。我使用这一行:

const modes = ['DRAW', 'SCALE', 'DRAG'].reduce((o, v) => ({ ...o, [v]: v }), {});

它生成具有人类可读值的对象:

{
  DRAW: 'DRAW',
  SCALE: 'SCALE',
  DRAG: 'DRAG'
}

其他回答

您可以使用一个简单的函数来反转键和值,当它将数字整数字符串转换为数字时,它也可以处理数组。代码小、简单,可用于此用例和其他用例。

var objInvert=函数(obj){var反转={}for(对象中的变量i){如果(i.match(/^\d+$/))i=parseInt(i,10)反转[obj[i]]=i}返回反转}var musicStyles=对象冻结(objInvert(['ROCK','SURF','METAL',“BOSSA-NOVA”、“op”、“die”]))console.log(音乐样式)

更新

我认为我下面的答案不再是用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

我一直在摆弄这个,因为我喜欢我的遗珠

使用Object.defineProperty,我想我找到了一个可行的解决方案。

这里有一个jsfiddle:http://jsfiddle.net/ZV4A6/

使用此方法。。理论上,您应该能够为任何对象调用和定义枚举值,而不会影响该对象的其他属性。

Object.defineProperty(Object.prototype,'Enum', {
    value: function() {
        for(i in arguments) {
            Object.defineProperty(this,arguments[i], {
                value:parseInt(i),
                writable:false,
                enumerable:true,
                configurable:true
            });
        }
        return this;
    },
    writable:false,
    enumerable:false,
    configurable:false
}); 

由于属性可写:false,这应该使其类型安全。

因此,您应该能够创建一个自定义对象,然后对其调用Enum()。分配的值从0开始,每项递增。

var EnumColors={};
EnumColors.Enum('RED','BLUE','GREEN','YELLOW');
EnumColors.RED;    // == 0
EnumColors.BLUE;   // == 1
EnumColors.GREEN;  // == 2
EnumColors.YELLOW; // == 3

尽管ES2015中只支持静态方法(而不支持静态财产)(请参见§15.2.2.2),但奇怪的是,您可以将以下内容用于Babel和ES2015预设:

class CellState {
    v: string;
    constructor(v: string) {
        this.v = v;
        Object.freeze(this);
    }
    static EMPTY       = new CellState('e');
    static OCCUPIED    = new CellState('o');
    static HIGHLIGHTED = new CellState('h');
    static values      = function(): Array<CellState> {
        const rv = [];
        rv.push(CellState.EMPTY);
        rv.push(CellState.OCCUPIED);
        rv.push(CellState.HIGHLIGHTED);
        return rv;
    }
}
Object.freeze(CellState);

我发现,即使在模块之间(例如,从另一个模块导入CellState枚举),以及在使用Webpack导入模块时,这也能正常工作。

与大多数其他答案相比,此方法的优势在于,您可以将其与静态类型检查器(例如Flow)一起使用,并且您可以在开发时使用静态类型检查断言您的变量、参数等是特定的CellState“enum”,而不是其他枚举(如果您使用了泛型对象或符号,则无法区分)。

使现代化

上面的代码有一个缺点,即它允许创建CellState类型的其他对象(尽管由于CellState被冻结,因此无法将它们分配给CellState的静态字段)。尽管如此,以下更精细的代码提供了以下优点:

不能再创建CellState类型的对象可以保证没有两个枚举实例分配了相同的代码从字符串表示中获取枚举的实用方法返回枚举的所有实例的values函数不必以上述手动(且容易出错)的方式创建返回值。“使用严格”;类状态{构造函数(code,displayName=code){if(Status.INSTANCES.has(代码))抛出新错误(`重复代码值:[${code}]`);if(!Status.canCreateMoreInstances)throw new Error(`尝试调用构造函数(${code}`+`,${displayName})在创建所有静态实例后`);this.code=代码;this.displayName=显示名称;对象.冻结(this);Status.INSTANCES.set(this.code,this);}到字符串(){return `[code:${this.code},displayName:${this.displayName}]`;}静态INSTANCES=新映射();静态canCreateMoreInstances=true;//值:静态ARCHIVED=新状态(“存档”);静态观察=新状态(“观察”);静态调度=新状态(“调度”);静态UNOBERVED=新状态(“未观察”);static UNTRIGGERED=新状态(“未触发”);静态值=函数(){return Array.from(Status.INSTANCES.values());}静态fromCode(代码){if(!Status.INSTANCES.has(代码))抛出新错误(“未知代码:${code}”);其他的return Status.INSTANCES.get(代码);}}Status.canCreateMoreInstances=false;对象冻结(状态);exports.Status=状态;

你的答案太复杂了

var buildSet = function(array) {
  var set = {};
  for (var i in array) {
    var item = array[i];
    set[item] = item;
  }
  return set;
}

var myEnum = buildSet(['RED','GREEN','BLUE']);
// myEnum.RED == 'RED' ...etc