在JavaScript中定义枚举的首选语法是什么?

在JavaScript中定义枚举的首选语法是什么?就像是:

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

// later on

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

还是有更好的成语?

猿神奇梅2020/03/09 18:25:55

你可以做这样的事情

    var Enum = (function(foo) {

    var EnumItem = function(item){
        if(typeof item == "string"){
            this.name = item;
        } else {
            this.name = item.name;
        }
    }
    EnumItem.prototype = new String("DEFAULT");
    EnumItem.prototype.toString = function(){
        return this.name;
    }
    EnumItem.prototype.equals = function(item){
        if(typeof item == "string"){
            return this.name == item;
        } else {
            return this == item && this.name == item.name;
        }
    }

    function Enum() {
        this.add.apply(this, arguments);
        Object.freeze(this);
    }
    Enum.prototype.add = function() {
        for (var i in arguments) {
            var enumItem = new EnumItem(arguments[i]);
            this[enumItem.name] = enumItem;
        }
    };
    Enum.prototype.toList = function() {
        return Object.keys(this);
    };
    foo.Enum = Enum;
    return Enum;
})(this);
var STATUS = new Enum("CLOSED","PENDING", { name : "CONFIRMED", ackd : true });
var STATE = new Enum("CLOSED","PENDING","CONFIRMED",{ name : "STARTED"},{ name : "PROCESSING"});

如该库中所定义。 https://github.com/webmodule/foo/blob/master/foo.js#L217

完整示例 https://gist.github.com/lnt/bb13a2fd63cdb8bce85fd62965a20026

2020/03/09 18:25:55

最简单的解决方案:

创建

var Status = Object.freeze({
    "Connecting":0,
    "Ready":1,
    "Loading":2,
    "Processing": 3
});

获得价值

console.log(Status.Ready) // 1

取得金钥

console.log(Object.keys(Status)[Status.Ready]) // Ready
Jim理查德2020/03/09 18:25:55

这是实现TypeScript枚举的几种不同方法

最简单的方法是仅迭代一个对象,向该对象添加反转的键值对。唯一的缺点是您必须手动设置每个成员的值。

function _enum(list) {       
  for (var key in list) {
    list[list[key] = list[key]] = key;
  }
  return Object.freeze(list);
}

var Color = _enum({
  Red: 0,
  Green: 5,
  Blue: 2
});

// Color → {0: "Red", 2: "Blue", 5: "Green", "Red": 0, "Green": 5, "Blue": 2}
// Color.Red → 0
// Color.Green → 5
// Color.Blue → 2
// Color[5] → Green
// Color.Blue > Color.Green → false


这是一个lodash mixin,用于使用字符串创建枚举。虽然此版本涉及更多点,但它会自动为您编号。本示例中使用的所有lodash方法都具有常规的JavaScript等效项,因此您可以根据需要轻松地将它们切换出来。

function enum() {
    var key, val = -1, list = {};
    _.reduce(_.toArray(arguments), function(result, kvp) {    
        kvp = kvp.split("=");
        key = _.trim(kvp[0]);
        val = _.parseInt(kvp[1]) || ++val;            
        result[result[val] = key] = val;
        return result;
    }, list);
    return Object.freeze(list);
}    

// Add enum to lodash 
_.mixin({ "enum": enum });

var Color = _.enum(
    "Red",
    "Green",
    "Blue = 5",
    "Yellow",
    "Purple = 20",
    "Gray"
);

// Color.Red → 0
// Color.Green → 1
// Color.Blue → 5
// Color.Yellow → 6
// Color.Purple → 20
// Color.Gray → 21
// Color[5] → Blue
达蒙理查德2020/03/09 18:25:55
var ColorEnum = {
    red: {},
    green: {},
    blue: {}
}

您无需确保不会以这种方式将重复的数字分配给不同的枚举值。实例化一个新对象并将其分配给所有枚举值。

→笑里藏刀↓2020/03/09 18:25:55

如果您使用的骨干,你可以得到全面的枚举功能免费使用(通过ID,名称,自定义成员找到)Backbone.Collection

// enum instance members, optional
var Color = Backbone.Model.extend({
    print : function() {
        console.log("I am " + this.get("name"))
    }
});

// enum creation
var Colors = new Backbone.Collection([
    { id : 1, name : "Red", rgb : 0xFF0000},
    { id : 2, name : "Green" , rgb : 0x00FF00},
    { id : 3, name : "Blue" , rgb : 0x0000FF}
], {
    model : Color
});

// Expose members through public fields.
Colors.each(function(color) {
    Colors[color.get("name")] = color;
});

// using
Colors.Red.print()
逆天米亚2020/03/09 18:25:55

我知道这是一个古老的方法,但是此后通过TypeScript接口实现的方法是:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["Foo"] = 0] = "Foo";
    MyEnum[MyEnum["FooBar"] = 2] = "FooBar";
    MyEnum[MyEnum["Bar"] = 1] = "Bar";
})(MyEnum|| (MyEnum= {}));

这样MyEnum.Bar一来,MyEnum[1]无论声明的顺序如何,都可以查找返回1以及返回“ Bar”的这两者

十三LEY2020/03/09 18:25:55

ES7中,您可以依靠静态属性进行优雅的ENUM:

class ColorEnum  {
    static RED = 0 ;
    static GREEN = 1;
    static BLUE = 2;
}

然后

if (currentColor === ColorEnum.GREEN ) {/*-- coding --*/}

优点(使用类而不是文字对象)是拥有父类,Enum然后您所有的Enums都将扩展该类。

 class ColorEnum  extends Enum {/*....*/}
神奇启人2020/03/09 18:25:54

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

话虽这么说,因为值无关紧要(您使用过0、1、2),所以如果您想输出当前值,我将使用有意义的字符串。

凯神无2020/03/09 18:25:54

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

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

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

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

柱塞演示

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
路易飞云2020/03/09 18:25:54

底线:不能。

您可以伪造它,但不会获得类型安全性。通常,这是通过创建映射到整数值的字符串值的简单字典来完成的。例如:

var DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}

Document.Write("Enumerant: " + DaysEnum.tuesday);

这种方法有问题吗?您可能会意外地重新定义您的枚举数,或者意外地具有重复的枚举数值。例如:

DaysEnum.monday = 4; // whoops, monday is now thursday, too

编辑

那么Artur Czajka的Object.freeze呢?这样是否可以防止您将星期一设置为星期四?– Fry Quad

绝对Object.freeze可以完全解决我抱怨的问题。我想提醒大家,当我写上面的文章时,Object.freeze实际上并不存在。

现在....现在它提供了一些非常有趣的可能性。

编辑2
这是一个用于创建枚举的很好的库。

http://www.2ality.com/2011/10/enums.html

尽管它可能不适合枚举的所有有效用法,但它的路途很长。

老丝阿飞2020/03/09 18:25:54

从1.8.5开始,可以密封和冻结对象,因此将以上定义为:

const DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})

要么

const DaysEnum = {"monday":1, "tuesday":2, "wednesday":3, ...}
Object.freeze(DaysEnum)

和瞧!JS枚举。

但是,这不会阻止您为变量分配不需要的值,这通常是枚举的主要目标:

let day = DaysEnum.tuesday
day = 298832342 // goes through without any errors

确保类型安全性(使用枚举或其他方式)的程度更高的一种方法是使用诸如TypeScriptFlow之类的工具

资源

不需要引号,但为了保持一致性,我保留了它们。