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

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

// later on

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

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


当前回答

这里有两种实现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

其他回答

你可以试试这个:

   var Enum = Object.freeze({
            Role: Object.freeze({ Administrator: 1, Manager: 2, Supervisor: 3 }),
            Color:Object.freeze({RED : 0, GREEN : 1, BLUE : 2 })
            });

    alert(Enum.Role.Supervisor);
    alert(Enum.Color.GREEN);
    var currentColor=0;
    if(currentColor == Enum.Color.RED) {
       alert('Its Red');
    }

您只需要使用object.freeze(<your_object>)创建一个不可变的对象:

export const ColorEnum = Object.freeze({
    // you can only change the property values here
    // in the object declaration like in the Java enumaration
    RED: 0,
    GREEN: 1,
    BLUE: 2,
});

ColorEnum.RED = 22    // assigning here will throw an error
ColorEnum.VIOLET = 45 // even adding a new property will throw an error

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

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(音乐样式)

这是我知道的一个旧版本,但它通过TypeScript接口实现的方式是:

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

这使您能够查找返回1的MyEnum.Bar和返回“Bar”的MyEnum[1],无论声明的顺序如何。

尽管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=状态;