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

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

// later on

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

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


当前回答

IE8不支持冻结()方法。资料来源:http://kangax.github.io/compat-table/es5/,单击顶部的“显示过时的浏览器?”,然后检查IE8并冻结行列交叉点。

在我目前的游戏项目中,我使用了以下内容,因为很少有客户仍然使用IE8:

var CONST_WILD_TYPES = {
    REGULAR: 'REGULAR',
    EXPANDING: 'EXPANDING',
    STICKY: 'STICKY',
    SHIFTING: 'SHIFTING'
};

我们还可以做到:

var CONST_WILD_TYPES = {
    REGULAR: 'RE',
    EXPANDING: 'EX',
    STICKY: 'ST',
    SHIFTING: 'SH'
};

或者甚至是这样:

var CONST_WILD_TYPES = {
    REGULAR: '1',
    EXPANDING: '2',
    STICKY: '3',
    SHIFTING: '4'
};

最后一个,对于字符串来说似乎是最有效的,如果您让服务器和客户端交换这些数据,它会减少您的总带宽。当然,现在您有责任确保数据中没有冲突(RE、EX等必须唯一,1、2等也必须唯一)。请注意,为了向后兼容,您需要永远保持这些。

分配:

var wildType = CONST_WILD_TYPES.REGULAR;

对比:

if (wildType === CONST_WILD_TYPES.REGULAR) {
    // do something here
}

其他回答

我修改了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

我对任何答案都不满意,所以我制作了《又一个枚举》(YEA!)。

此实施:

使用最新的JS只需要这一类的声明即可轻松创建enum具有按名称(colors.RED)、字符串(colors[“RED”])和索引(colors[0])进行的映射,但只需将字符串作为数组传递将等价于String()和valueOf()函数绑定到每个enum对象(如果不希望这样做,可以简单地删除它-不过JS的开销很小)具有可选的全局命名/存储(按名称字符串)创建后冻结枚举对象,使其无法修改

特别感谢Andre‘Fi的回答给了我们一些启发。


代码:

class Enums {
  static create({ name = undefined, items = [] }) {
    let newEnum = {};
    newEnum.length = items.length;
    newEnum.items = items;
    for (let itemIndex in items) {
      //Map by name.
      newEnum[items[itemIndex]] = parseInt(itemIndex, 10);
      //Map by index.
      newEnum[parseInt(itemIndex, 10)] = items[itemIndex];
    }
    newEnum.toString = Enums.enumToString.bind(newEnum);
    newEnum.valueOf = newEnum.toString;
    //Optional naming and global registration.
    if (name != undefined) {
      newEnum.name = name;
      Enums[name] = newEnum;
    }
    //Prevent modification of the enum object.
    Object.freeze(newEnum);
    return newEnum;
  }
  static enumToString() {
    return "Enum " +
      (this.name != undefined ? this.name + " " : "") +
      "[" + this.items.toString() + "]";
  }
}

用法:

let colors = Enums.create({
  name: "COLORS",
  items: [ "RED", "GREEN", "BLUE", "PORPLE" ]
});

//Global access, if named.
Enums.COLORS;

colors.items; //Array(4) [ "RED", "GREEN", "BLUE", "PORPLE" ]
colors.length; //4

colors.RED; //0
colors.GREEN; //1
colors.BLUE; //2
colors.PORPLE; //3
colors[0]; //"RED"
colors[1]; //"GREEN"
colors[2]; //"BLUE"
colors[3]; //"PORPLE"

colors.toString(); //"Enum COLORS [RED,GREEN,BLUE,PORPLE]"

//Enum frozen, makes it a real enum.
colors.RED = 9001;
colors.RED; //0

我制作了一个Enum类,它可以在O(1)处获取值和名称。它还可以生成包含所有名称和值的对象数组。

function Enum(obj) {
    // Names must be unique, Values do not.
    // Putting same values for different Names is risky for this implementation

    this._reserved = {
        _namesObj: {},
        _objArr: [],
        _namesArr: [],
        _valuesArr: [],
        _selectOptionsHTML: ""
    };

    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            this[k] = obj[k];
            this._reserved._namesObj[obj[k]] = k;
        }
    }
}
(function () {
    this.GetName = function (val) {
        if (typeof this._reserved._namesObj[val] === "undefined")
            return null;
        return this._reserved._namesObj[val];
    };

    this.GetValue = function (name) {
        if (typeof this[name] === "undefined")
            return null;
        return this[name];
    };

    this.GetObjArr = function () {
        if (this._reserved._objArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push({
                            Name: k,
                            Value: this[k]
                        });
            }
            this._reserved._objArr = arr;
        }
        return this._reserved._objArr;
    };

    this.GetNamesArr = function () {
        if (this._reserved._namesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(k);
            }
            this._reserved._namesArr = arr;
        }
        return this._reserved._namesArr;
    };

    this.GetValuesArr = function () {
        if (this._reserved._valuesArr.length == 0) {
            var arr = [];
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        arr.push(this[k]);
            }
            this._reserved._valuesArr = arr;
        }
        return this._reserved._valuesArr;
    };

    this.GetSelectOptionsHTML = function () {
        if (this._reserved._selectOptionsHTML.length == 0) {
            var html = "";
            for (k in this) {
                if (this.hasOwnProperty(k))
                    if (k != "_reserved")
                        html += "<option value='" + this[k] + "'>" + k + "</option>";
            }
            this._reserved._selectOptionsHTML = html;
        }
        return this._reserved._selectOptionsHTML;
    };
}).call(Enum.prototype);

您可以这样初始化:

var enum1 = new Enum({
    item1: 0,
    item2: 1,
    item3: 2
});

要获取值(如C#中的枚举):

var val2 = enum1.item2;

要获取某个值的名称(将相同的值用于不同的名称时可能会不明确):

var name1 = enum1.GetName(0);  // "item1"

要获取对象中每个名称和值的数组,请执行以下操作:

var arr = enum1.GetObjArr();

将生成:

[{ Name: "item1", Value: 0}, { ... }, ... ]

您还可以轻松获得html选择选项:

var html = enum1.GetSelectOptionsHTML();

其中包含:

"<option value='0'>item1</option>..."

最简单的解决方案:

创造

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

这不是一个很好的答案,但我个人认为这很好

话虽如此,因为值是什么并不重要(您使用了0、1、2),所以我会使用一个有意义的字符串,以防您想要输出当前值。