以下是否会使对象满足枚举在 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
}
或者我还有其他方法可以做到这一点吗?
从 1.8.5 开始可以密封和冻结 object,因此将上述定义为:
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
确保更高程度的类型安全(使用枚举或其他方式)的一种方法是使用像TypeScript或Flow这样的工具。
不需要引号,但我保留它们以保持一致性。
这不是一个很好的答案,但我会说,就个人而言,这很好用
话虽如此,因为值是什么并不重要(您使用了 0、1、2),所以如果您想输出当前值,我会使用一个有意义的字符串。
感谢大家的支持,但我认为我下面的回答不再是在 JavaScript 中编写枚举的最佳方式。有关更多详细信息,请参阅我的博客文章:JavaScript 中的枚举。
已经可以警告名称:
if (currentColor == my.namespace.ColorEnum.RED) {
// alert name of currentColor (RED: 0)
var col = my.namespace.ColorEnum;
for (var name in col) {
if (col[name] == col.RED)
alert(name);
}
}
或者,您可以创建 values 对象,这样您就可以拥有蛋糕并吃掉它:
var SIZE = {
SMALL : {value: 0, name: "Small", code: "S"},
MEDIUM: {value: 1, name: "Medium", code: "M"},
LARGE : {value: 2, name: "Large", code: "L"}
};
var currentSize = SIZE.MEDIUM;
if (currentSize == SIZE.MEDIUM) {
// this alerts: "1: Medium"
alert(currentSize.value + ": " + currentSize.name);
}
在 JavaScript 中,由于它是一种动态语言,甚至可以稍后将枚举值添加到集合中:
// Add EXTRALARGE size
SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"};
请记住,身份检查不需要枚举的字段(本示例中的值、名称和代码),它们只是为了方便起见。此外,size 属性本身的名称不需要硬编码,但也可以动态设置。因此,假设您只知道新枚举值的名称,您仍然可以毫无问题地添加它:
// Add 'Extra Large' size, only knowing it's name
var name = "Extra Large";
SIZE[name] = {value: -1, name: name, code: "?"};
当然,这意味着不能再进行某些假设(例如,该值表示大小的正确顺序)。
请记住,在 JavaScript 中,对象就像地图或哈希表。一组名称-值对。您可以遍历它们或以其他方式操纵它们,而无需事先了解它们。
for (var sz in SIZE) {
// sz will be the names of the objects in SIZE, so
// 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'
var size = SIZE[sz]; // Get the object mapped to the name in sz
for (var prop in size) {
// Get all the properties of the size object, iterates over
// 'value', 'name' and 'code'. You can inspect everything this way.
}
}
顺便说一句,如果你对命名空间感兴趣,你可能想看看我的简单但强大的 JavaScript 命名空间和依赖管理解决方案:Packages JS
底线:你不能。
你可以伪造它,但你不会得到类型安全。通常,这是通过创建映射到整数值的字符串值的简单字典来完成的。例如:
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 怎么样?这不会阻止您将星期一设置为星期四吗?– 油炸四边形
绝对Object.freeze
会完全解决我抱怨的问题。我想提醒大家,当我写上面的时候,Object.freeze
实际上并不存在。
现在......现在它开辟了一些非常有趣的可能性。
编辑 2
这是一个非常好的用于创建枚举的库。
http://www.2ality.com/2011/10/enums.html
虽然它可能不适合枚举的所有有效使用,但它有很长的路要走。
这是我们都想要的:
function Enum(constantsList) {
for (var i in constantsList) {
this[constantsList[i]] = i;
}
}
现在您可以创建您的枚举:
var YesNo = new Enum(['NO', 'YES']);
var Color = new Enum(['RED', 'GREEN', 'BLUE']);
通过这样做,可以以通常的方式访问常量(YesNo.YES,Color.GREEN),并且它们会得到一个连续的 int 值(NO = 0,YES = 1;RED = 0,GREEN = 1,BLUE = 2)。
您还可以使用 Enum.prototype 添加方法:
Enum.prototype.values = function() {
return this.allValues;
/* for the above to work, you'd need to do
this.allValues = constantsList at the constructor */
};
编辑 - 小改进 - 现在使用可变参数:(不幸的是它在 IE 上不能正常工作:S ...应该坚持使用以前的版本)
function Enum() {
for (var i in arguments) {
this[arguments[i]] = i;
}
}
var YesNo = new Enum('NO', 'YES');
var Color = new Enum('RED', 'GREEN', 'BLUE');