以下内容是否会使对象满足枚举在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
}
还是有其他方法可以做到这一点?
当前回答
你可以试试这个:
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');
}
其他回答
截至2014年10月的撰写,这里有一个当代的解决方案。我将解决方案作为节点模块编写,并使用Mocha和Chai以及undercoreJS进行了测试。您可以很容易地忽略这些,如果愿意,只需使用Enum代码。
看到了很多带有过于复杂的库等的帖子。在Javascript中获得枚举支持的解决方案非常简单,真的不需要。代码如下:
文件:enums.js
_ = require('underscore');
var _Enum = function () {
var keys = _.map(arguments, function (value) {
return value;
});
var self = {
keys: keys
};
for (var i = 0; i < arguments.length; i++) {
self[keys[i]] = i;
}
return self;
};
var fileFormatEnum = Object.freeze(_Enum('CSV', 'TSV'));
var encodingEnum = Object.freeze(_Enum('UTF8', 'SHIFT_JIS'));
exports.fileFormatEnum = fileFormatEnum;
exports.encodingEnum = encodingEnum;
还有一个测试来说明它给你带来了什么:
文件:enumsSpec.js
var chai = require("chai"),
assert = chai.assert,
expect = chai.expect,
should = chai.should(),
enums = require('./enums'),
_ = require('underscore');
describe('enums', function () {
describe('fileFormatEnum', function () {
it('should return expected fileFormat enum declarations', function () {
var fileFormatEnum = enums.fileFormatEnum;
should.exist(fileFormatEnum);
assert('{"keys":["CSV","TSV"],"CSV":0,"TSV":1}' === JSON.stringify(fileFormatEnum), 'Unexpected format');
assert('["CSV","TSV"]' === JSON.stringify(fileFormatEnum.keys), 'Unexpected keys format');
});
});
describe('encodingEnum', function () {
it('should return expected encoding enum declarations', function () {
var encodingEnum = enums.encodingEnum;
should.exist(encodingEnum);
assert('{"keys":["UTF8","SHIFT_JIS"],"UTF8":0,"SHIFT_JIS":1}' === JSON.stringify(encodingEnum), 'Unexpected format');
assert('["UTF8","SHIFT_JIS"]' === JSON.stringify(encodingEnum.keys), 'Unexpected keys format');
});
});
});
正如您所看到的,您获得了一个Enum工厂,只需调用Enum.keys即可获得所有键,并且可以将键本身与整数常量匹配。您可以使用不同的值重用工厂,并使用Node的模块化方法导出生成的Enum。
同样,如果您只是一个普通用户,或者在浏览器等中,只需使用代码的工厂部分,如果您不想在代码中使用下划线库,也可能会删除它。
我修改了Andre“Fi”的解决方案:
function Enum() {
var that = this;
for (var i in arguments) {
that[arguments[i]] = i;
}
this.name = function(value) {
for (var key in that) {
if (that[key] == value) {
return key;
}
}
};
this.exist = function(value) {
return (typeof that.name(value) !== "undefined");
};
if (Object.freeze) {
Object.freeze(that);
}
}
测试:
var Color = new Enum('RED', 'GREEN', 'BLUE');
undefined
Color.name(Color.REDs)
undefined
Color.name(Color.RED)
"RED"
Color.exist(Color.REDs)
false
Color.exist(Color.RED)
true
我也在寻找这个问题的答案,并找到了这一页的答案,我认为答案与这里的大多数答案不同: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将产生更好的代码更稳定、更容易阅读和更少出错。
es7方式,(迭代器,冻结),用法:
const ThreeWiseMen = new Enum('Melchior', 'Caspar', 'Balthazar')
for (let name of ThreeWiseMen)
console.log(name)
// with a given key
let key = ThreeWiseMen.Melchior
console.log(key in ThreeWiseMen) // true (string conversion, also true: 'Melchior' in ThreeWiseMen)
for (let entry from key.enum)
console.log(entry)
// prevent alteration (throws TypeError in strict mode)
ThreeWiseMen.Me = 'Me too!'
ThreeWiseMen.Melchior.name = 'Foo'
代码:
class EnumKey {
constructor(props) { Object.freeze(Object.assign(this, props)) }
toString() { return this.name }
}
export class Enum {
constructor(...keys) {
for (let [index, key] of keys.entries()) {
Object.defineProperty(this, key, {
value: new EnumKey({ name:key, index, enum:this }),
enumerable: true,
})
}
Object.freeze(this)
}
*[Symbol.iterator]() {
for (let key of Object.keys(this))
yield this[key]
}
toString() { return [...this].join(', ') }
}
这个答案是针对特定情况的另一种方法。我需要一组基于属性子值的位掩码常量(属性值是数组或值列表的情况)。它包含几个重叠枚举的等价物。
我创建了一个类来存储和生成位掩码值。然后,我可以用这种方式使用伪常量位掩码值来测试,例如,如果RGB值中存在绿色:
if (value & Ez.G) {...}
在我的代码中,我只创建了这个类的一个实例。在不实例化类的至少一个实例的情况下,似乎没有一种干净的方法可以做到这一点。以下是类声明和位掩码值生成代码:
class Ez {
constructor() {
let rgba = ["R", "G", "B", "A"];
let rgbm = rgba.slice();
rgbm.push("M"); // for feColorMatrix values attribute
this.createValues(rgba);
this.createValues(["H", "S", "L"]);
this.createValues([rgba, rgbm]);
this.createValues([attX, attY, attW, attH]);
}
createValues(a) { // a for array
let i, j;
if (isA(a[0])) { // max 2 dimensions
let k = 1;
for (i of a[0]) {
for (j of a[1]) {
this[i + j] = k;
k *= 2;
}
}
}
else { // 1D array is simple loop
for (i = 0, j = 1; i < a.length; i++, j *= 2)
this[a[i]] = j;
}
}
2D数组用于SVG feColorMatrix值属性,该属性是RGBA和RGBAM的4x5矩阵,其中M是乘数。得到的Ez财产为Ez.RR、Ez.RG等。