以下内容是否会使对象满足枚举在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 DaysEnum = Object.freeze ({ monday: {}, tuesday: {}, ... });
您不需要指定id,只需使用空对象来比较枚举即可。
if (incommingEnum === DaysEnum.monday) //incommingEnum is monday
EDIT:如果要序列化对象(例如JSON),将再次输入id。
(摘自加布里埃尔·利亚马斯评论)(根据Stijn de Witt的评论进行编辑)
其他回答
这是我对一个(标记的)Enum工厂的看法。这是一个工作演示。
/*
* Notes:
* The proxy handler enables case insensitive property queries
* BigInt is used to enable bitflag strings /w length > 52
*/
function EnumFactory() {
const proxyfy = {
construct(target, args) {
const caseInsensitiveHandler = {
get(target, key) {
return target[key.toUpperCase()] || target[key];
}
};
const proxified = new Proxy(new target(...args), caseInsensitiveHandler );
return Object.freeze(proxified);
},
}
const ProxiedEnumCtor = new Proxy(EnumCtor, proxyfy);
const throwIf = (
assertion = false,
message = `Unspecified error`,
ErrorType = Error ) =>
assertion && (() => { throw new ErrorType(message); })();
const hasFlag = (val, sub) => {
throwIf(!val || !sub, "valueIn: missing parameters", RangeError);
const andVal = (sub & val);
return andVal !== BigInt(0) && andVal === val;
};
function EnumCtor(values) {
throwIf(values.constructor !== Array ||
values.length < 2 ||
values.filter( v => v.constructor !== String ).length > 0,
`EnumFactory: expected Array of at least 2 strings`, TypeError);
const base = BigInt(1);
this.NONE = BigInt(0);
values.forEach( (v, i) => this[v.toUpperCase()] = base<<BigInt(i) );
}
EnumCtor.prototype = {
get keys() { return Object.keys(this).slice(1); },
subset(sub) {
const arrayValues = this.keys;
return new ProxiedEnumCtor(
[...sub.toString(2)].reverse()
.reduce( (acc, v, i) => ( +v < 1 ? acc : [...acc, arrayValues[i]] ), [] )
);
},
getLabel(enumValue) {
const tryLabel = Object.entries(this).find( value => value[1] === enumValue );
return !enumValue || !tryLabel.length ?
"getLabel: no value parameter or value not in enum" :
tryLabel.shift();
},
hasFlag(val, sub = this) { return hasFlag(val, sub); },
};
return arr => new ProxiedEnumCtor(arr);
}
真的很像@Duncan上面所做的,但我不喜欢用Enum破坏全局Object函数空间,所以我写了以下内容:
function mkenum_1()
{
var o = new Object();
var c = -1;
var f = function(e, v) { Object.defineProperty(o, e, { value:v, writable:false, enumerable:true, configurable:true })};
for (i in arguments) {
var e = arguments[i];
if ((!!e) & (e.constructor == Object))
for (j in e)
f(j, (c=e[j]));
else
f(e, ++c);
}
return Object.freeze ? Object.freeze(o) : o;
}
var Sizes = mkenum_1('SMALL','MEDIUM',{LARGE: 100},'XLARGE');
console.log("MED := " + Sizes.MEDIUM);
console.log("LRG := " + Sizes.LARGE);
// Output is:
// MED := 1
// LRG := 100
@Stijin也有一个简洁的解决方案(参考他的博客),其中包括这些对象的财产。我也为此写了一些代码,接下来我会把它包括在内。
function mkenum_2(seed)
{
var p = {};
console.log("Seed := " + seed);
for (k in seed) {
var v = seed[k];
if (v instanceof Array)
p[(seed[k]=v[0])] = { value: v[0], name: v[1], code: v[2] };
else
p[v] = { value: v, name: k.toLowerCase(), code: k.substring(0,1) };
}
seed.properties = p;
return Object.freeze ? Object.freeze(seed) : seed;
}
此版本生成了一个允许友好名称转换和短代码的附加属性列表。我喜欢这个版本,因为不需要像代码那样在财产中重复数据输入。
var SizeEnum2 = mkenum_2({ SMALL: 1, MEDIUM: 2, LARGE: 3});
var SizeEnum3 = mkenum_2({ SMALL: [1, "small", "S"], MEDIUM: [2, "medium", "M"], LARGE: [3, "large", "L"] });
这两者可以组合成一个处理单元mkenum(使用enum、分配值、创建和添加属性列表)。然而,由于我今天已经在这方面花了太多时间,我将把这个组合作为练习留给亲爱的读者。
创建对象文字:
const Modes = {
DRAGGING: 'drag',
SCALING: 'scale',
CLICKED: 'click'
};
我不久前使用了__defineGetter__和__defineSetter__或defineProperty的组合,具体取决于JS版本。
下面是我制作的枚举生成函数:https://gist.github.com/gfarrell/6716853
你可以这样使用:
var Colours = Enum('RED', 'GREEN', 'BLUE');
它将创建一个不可变的字符串:int字典(一个枚举)。
最简单的解决方案:
创造
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