以下内容是否会使对象满足枚举在JavaScript中的所有特性?类似于:
my.namespace.ColorEnum = {
RED : 0,
GREEN : 1,
BLUE : 2
}
// later on
if(currentColor == my.namespace.ColorEnum.RED) {
// whatever
}
还是有其他方法可以做到这一点?
以下内容是否会使对象满足枚举在JavaScript中的所有特性?类似于:
my.namespace.ColorEnum = {
RED : 0,
GREEN : 1,
BLUE : 2
}
// later on
if(currentColor == my.namespace.ColorEnum.RED) {
// whatever
}
还是有其他方法可以做到这一点?
当前回答
尽管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 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(音乐样式)
你可以这样做
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
我也在寻找这个问题的答案,并找到了这一页的答案,我认为答案与这里的大多数答案不同:https://www.sohamkamani.com/javascript/enums/
我将把文章的答案部分复制到这里,以防将来链接无效或其他情况:
带符号的枚举:符号让我们定义保证不会冲突的值彼此之间。例如:
const Summer1 = Symbol("summer")
const Summer2 = Symbol("summer")
// Even though they have the same apparent value
// Summer1 and Summer2 don't equate
console.log(Summer1 === Summer2)
// false
console.log(Summer1)
我们可以使用符号定义枚举,以确保它们不是复制:
const Summer = Symbol("summer")
const Autumn = Symbol("autumn")
const Winter = Symbol("winter")
const Spring = Symbol("spring")
let season = Spring
switch (season) {
case Summer:
console.log('the season is summer')
break;
case Winter:
console.log('the season is winter')
break;
case Spring:
console.log('the season is spring')
break;
case Autumn:
console.log('the season is autumn')
break;
default:
console.log('season not defined')
}
使用Symbol可以确保我们分配枚举值的唯一方法是使用我们最初定义的常量。
具有类的枚举:
为了使代码更加语义正确,我们可以创建一个类保存一组枚举。例如,我们的季节应该有一种方法来识别它们都属于类似的分类。让我们看看如何使用类和对象创建不同的枚举组:
// Season enums can be grouped as static members of a class
class Season {
// Create new instances of the same class as static attributes
static Summer = new Season("summer")
static Autumn = new Season("autumn")
static Winter = new Season("winter")
static Spring = new Season("spring")
constructor(name) {
this.name = name
}
}
// Now we can access enums using namespaced assignments
// this makes it semantically clear that "Summer" is a "Season"
let season = Season.Summer
// We can verify whether a particular variable is a Season enum
console.log(season instanceof Season)
// true
console.log(Symbol('something') instanceof Season)
//false
// We can explicitly check the type based on each enums class
console.log(season.constructor.name)
// 'Season'
个人注意:我本应该使用此构造函数:(注意:将this.name设置为字符串而不是对象,会丢失以下一些验证。可以选择删除:.description。我还想找到一种方法,不必键入Seasons.summer.name,而只需:Seasons.summer即可使其返回字符串)
constructor(name) {
this.name = Symbol(name).description
}
列出所有可能的枚举值:
如果我们使用上述基于类的方法Season类的键,以获取同一类下的所有枚举值组:
Object.keys(Season).forEach(season => console.log("season:", season))
// season: Summer
// season: Autumn
// season: Winter
// season: Spring
何时在Javascript中使用枚举?
通常,如果有一定数量的固定任何一个变量的值_例如,Node.js的加密标准库有一个受支持的算法列表,可以将其视为枚举组。正确使用Javascript中的enums将产生更好的代码更稳定、更容易阅读和更少出错。
这可能很有用:
const [CATS, DOGS, BIRDS] = ENUM();
实施简单高效:
function * ENUM(count=1) { while(true) yield count++ }
生成器可以产生所需的整数的精确序列,而不知道有多少常数。它还可以支持一个可选参数,该参数指定从哪个(可能是负数)数字开始(默认为1)。
这是我知道的一个旧版本,但它通过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],无论声明的顺序如何。