以下内容是否会使对象满足枚举在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的评论进行编辑)

其他回答

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
}

在我看来,枚举是什么?它是一个不可变的对象,总是可以访问,您可以相互比较项目,但项目具有通用的财产/方法,但对象本身或值不能更改,它们只能实例化一次。

枚举用于比较数据类型、设置、采取/回复的操作等。

为此,您需要具有相同实例的对象,以便您可以检查它是否为枚举类型if(something instanceof enum)此外,如果您获得了一个枚举对象,则无论枚举类型如何,它都应该以相同的方式进行响应。

在我的例子中,它比较数据类型的值,但它可以是任何东西,从在3d游戏中修改面向方向的块到将值传递到特定的对象类型注册表。

请记住,它是javascript,不提供固定的枚举类型,您最终总是自己实现,正如本线程所示,有很多实现都不正确。


这是我用于枚举的内容。由于枚举是不可变的(或者至少应该是呵呵),所以我冻结了对象,这样它们就不容易被操作了。

枚举可以由EnumField.STRING使用,并且它们有自己的方法来处理它们的类型。要测试是否有东西传递给对象,可以使用if(somevar instanceof EnumFieldSegment)

这可能不是最优雅的解决方案,我愿意改进,但这种类型的不可变枚举(除非你解冻它)正是我需要的用例。

我也意识到我可以用{}重写原型,但我的大脑在这种格式下工作得更好;-)向我开枪。

/**
 * simple parameter object instantiator
 * @param name
 * @param value
 * @returns
 */
function p(name,value) {
    this.name = name;
    this.value = value;
    return Object.freeze(this);
}
/**
 * EnumFieldSegmentBase
 */
function EnumFieldSegmentBase() {
    this.fieldType = "STRING";
}
function dummyregex() {
}
dummyregex.prototype.test = function(str) {
    if(this.fieldType === "STRING") {
        maxlength = arguments[1];
        return str.length <= maxlength;
    }
    return true;
};

dummyregexposer = new dummyregex();
EnumFieldSegmentBase.prototype.getInputRegex = function() { 
    switch(this.fieldType) {
        case "STRING" :     return dummyregexposer;  
        case "INT":         return /^(\d+)?$/;
        case "DECIMAL2":    return /^\d+(\.\d{1,2}|\d+|\.)?$/;
        case "DECIMAL8":    return /^\d+(\.\d{1,8}|\d+|\.)?$/;
        // boolean is tricky dicky. if its a boolean false, if its a string if its empty 0 or false its  false, otherwise lets see what Boolean produces
        case "BOOLEAN":     return dummyregexposer;
    }
};
EnumFieldSegmentBase.prototype.convertToType = function($input) {
    var val = $input;
    switch(this.fieldType) {
        case "STRING" :         val = $input;break;
        case "INT":         val==""? val=0 :val = parseInt($input);break;
        case "DECIMAL2":    if($input === "" || $input === null) {$input = "0"}if($input.substr(-1) === "."){$input = $input+0};val = new Decimal2($input).toDP(2);break;
        case "DECIMAL8":    if($input === "" || $input === null) {$input = "0"}if($input.substr(-1) === "."){$input = $input+0};val = new Decimal8($input).toDP(8);break;
        // boolean is tricky dicky. if its a boolean false, if its a string if its empty 0 or false its  false, otherwise lets see what Boolean produces
        case "BOOLEAN":     val = (typeof $input == 'boolean' ? $input : (typeof $input === 'string' ? (($input === "false" || $input === "" || $input === "0") ? false : true) : new Boolean($input).valueOf()))  ;break;
    }
    return val;
};
EnumFieldSegmentBase.prototype.convertToString = function($input) {
    var val = $input;
    switch(this.fieldType) {
        case "STRING":      val = $input;break;
        case "INT":         val = $input+"";break;
        case "DECIMAL2":    val = $input.toPrecision(($input.toString().indexOf('.') === -1 ? $input.toString().length+2 : $input.toString().indexOf('.')+2)) ;break;
        case "DECIMAL8":    val = $input.toPrecision(($input.toString().indexOf('.') === -1 ? $input.toString().length+8 : $input.toString().indexOf('.')+8)) ;break;
        case "BOOLEAN":     val = $input ? "true" : "false"  ;break;
    }
    return val;
};
EnumFieldSegmentBase.prototype.compareValue = function($val1,$val2) {
    var val = false;
    switch(this.fieldType) {
        case "STRING":      val = ($val1===$val2);break;
        case "INT":         val = ($val1===$val2);break;
        case "DECIMAL2":    val = ($val1.comparedTo($val2)===0);break;
        case "DECIMAL8":    val = ($val1.comparedTo($val2)===0);break;
        case "BOOLEAN":     val = ($val1===$val2);break;
    }
    return val;
};

/**
 * EnumFieldSegment is an individual segment in the 
 * EnumField
 * @param $array An array consisting of object p
 */
function EnumFieldSegment() {
    for(c=0;c<arguments.length;c++) {
        if(arguments[c] instanceof p) {
            this[arguments[c].name] = arguments[c].value;
        }
    }
    return Object.freeze(this); 
}
EnumFieldSegment.prototype = new EnumFieldSegmentBase();
EnumFieldSegment.prototype.constructor = EnumFieldSegment;


/**
 * Simple enum to show what type of variable a Field type is.
 * @param STRING
 * @param INT
 * @param DECIMAL2
 * @param DECIMAL8
 * @param BOOLEAN
 * 
 */
EnumField = Object.freeze({STRING:      new EnumFieldSegment(new p("fieldType","STRING")), 
                            INT:        new EnumFieldSegment(new p("fieldType","INT")), 
                            DECIMAL2:   new EnumFieldSegment(new p("fieldType","DECIMAL2")), 
                            DECIMAL8:   new EnumFieldSegment(new p("fieldType","DECIMAL8")), 
                            BOOLEAN:    new EnumFieldSegment(new p("fieldType","BOOLEAN"))});

我认为它很容易使用。https://stackoverflow.com/a/32245370/4365315

var A = {a:11, b:22}, 
enumA = new TypeHelper(A);

if(enumA.Value === A.b || enumA.Key === "a"){ 
... 
}

var keys = enumA.getAsList();//[object, object]

//set
enumA.setType(22, false);//setType(val, isKey)

enumA.setType("a", true);

enumA.setTypeByIndex(1);

更新:

这是我的助手代码(TypeHelper)。

var助手={isEmpty:函数(obj){回来obj | | obj===null | | obj===未定义| | Array.isArray(obj)&&obj.length===0;},isObject:函数(obj){return(对象类型==“object”);},sortObjectKeys:函数(对象){return Object.keys(对象).sort(函数(a,b){c=a-b;返回c});},containsItem:函数(arr,item){if(arr&&Array.isArray(arr)){return arr.indexOf(项)>-1;}其他{返回arr==项;}},pushArray:函数(arr1,arr2){if(arr1&&arr2&&Array.isArray(arr1)){arr1.push.apply(arr1,Array.isArray(arr2)?arr2:[arr2]);}}};函数TypeHelper(){var_types=参数[0],_defTypeIndex=0,_电流类型,_值,_allKeys=助手.sortObjectKeys(_types);if(arguments.length==2){_defTypeIndex=参数[1];}对象定义属性(this{关键字:{get:函数(){return _currentType;},集合:函数(val){_currentType.setType(val,true);},可枚举:真},值:{get:函数(){返回类型[_currentType];},集合:函数(val){_value.setType(val,false);},可枚举:真}});this.getAsList=函数(键){var列表=[];_allKeys.forEach(函数(键、idx、数组){if(键和类型[key]){if(!Helper.isEmpty(keys)&&Helper.containsItem(keys,key)|| Helper.isEmpty(key)){var json={};json.Key=密钥;json.Value=_types[key];Helper.pushArray(列表,json);}}});返回列表;};this.setType=函数(值,isKey){if(!Helper.isEmpty(value)){Object.keys(_types).forEach(函数(key,idx,array){if(Helper.isObject(值)){if(value&&value.Key==Key){_currentType=键;}}else if(isKey){if(value&&value.toString()==key.toString()){_currentType=键;}}否则如果(value&&value.toString()==_types[key]){_currentType=键;}});}其他{this.setDefaultType();}return isKey_类型[_currentType]:_currentType;};this.setTypeByIndex=函数(索引){对于(变量i=0;i<_allKeys.length;i++){如果(索引==i){_currentType=_allKeys[index];打破}}};this.setDefaultType=函数(){this.setTypeByIndex(_defTypeIndex);};this.setDefaultType();}变量类型A={“-1”:“任意”,“2”:“2L”,“100”:“100L”,“200”:“200L”,“1000”:“1000升”};var enumA=新的TypeHelper(TypeA,4);document.writeln(“Key=”,enumA.Key,”,Value=“,enumA.Value,”<br>“);enumA.setType(“200L”,假);document.writeln(“Key=”,enumA.Key,”,Value=“,enumA.Value,”<br>“);enumA.setDefaultType();document.writeln(“Key=”,enumA.Key,”,Value=“,enumA.Value,”<br>“);enumA.setTypeByIndex(1);document.writeln(“Key=”,enumA.Key,”,Value=“,enumA.Value,”<br>“);document.writeln(“等于=”,(enumA.Value==TypeA[“2”]));

您只需要使用object.freeze(<your_object>)创建一个不可变的对象:

export const ColorEnum = Object.freeze({
    // you can only change the property values here
    // in the object declaration like in the Java enumaration
    RED: 0,
    GREEN: 1,
    BLUE: 2,
});

ColorEnum.RED = 22    // assigning here will throw an error
ColorEnum.VIOLET = 45 // even adding a new property will throw an error

这个答案是针对特定情况的另一种方法。我需要一组基于属性子值的位掩码常量(属性值是数组或值列表的情况)。它包含几个重叠枚举的等价物。

我创建了一个类来存储和生成位掩码值。然后,我可以用这种方式使用伪常量位掩码值来测试,例如,如果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等。