0

因此,我受到这个问题(JavaScript 中的枚举?)的启发,开始着手为 JavaScript 插入库以启用不可修改的枚举。我已经定义了一个体面的工作方法,但我想进一步充实它。

这个概念利用Object.defineProperty(文档:Here

我目前的定义允许:

var obj1 = {}, obj2 = {}, obj3 = {};
// Straight declaration (normal)
obj1.Enum('RED','BLUE','GREEN');
obj1.RED    // == 0
obj1.BLUE   // == 1
obj1.GREEN  // == 2
// Buffer (padding) usage
obj2.Enum('RED','BLUE',null,undefined,'','GREEN');
obj2.RED    // == 0
obj2.BLUE   // == 1
obj2.GREEN  // == 5
// Direct offset and case-correction
obj3.Enum('RED','BLUE',10,'gReEn','burnt orange');
obj3.RED           // == 0
obj3.BLUE          // == 1
obj3.GREEN         // == 11
obj3.BURNT_ORANGE  // == 12

到目前为止我所拥有的:

var odp=Object.defineProperty;
odp(Object.prototype,'Enum', {
    value: function() {
        var ignore=[undefined,null,''], n=0, args=arguments;
        for(var i in args) {
            if(ignore.indexOf(args[i])<0) {
                if( typeof args[i]=="number") {
                    n=parseInt(args[i]);
                } else {
                    try {
                        odp(this,String(args[i]).toUpperCase().replace(" ","_"), {
                            value:parseInt(n),enumerable:true
                        });
                    } catch(e) {
                        console.warn(e.message);
                        n--;
                    }
                }
            }
            n++;
        }
        return this;
    }
});

我想补充的两件事是:

  1. 较旧的浏览器支持:因此,重新Object.defineProperty定义未定义的位置。(我目前无法访问旧版浏览器来测试可能的重新定义)
  2. 我可能错过了枚举定义的任何考虑。

jsFiddle:

注意:我拥有odp=Object.defineProperty并且args=arguments是我在将 JavaScript 插入我的页面之前通过闭包编译器运行它的原因,这样做有助于压缩。(对于那些可能想知道的人)

4

1 回答 1

2

较旧的浏览器支持:因此,重新Object.defineProperty定义未定义的位置。

你不能用你当前的方法做到这一点,因为你当前的方法扩展了Object.prototype. 如果您有 ES5 支持,则Object.prototype应该非常非常少地进行扩展,但如果没有它,则绝对不能这样做,因为没有Object.defineProperty,您将无法创建不可枚举的属性。添加可枚举属性Object.property将打破所有for-in循环。

不过,无论如何都没有理由Enum使用原型,只需将其放在Object(或您自己的库对象)上并将要枚举的对象传递给它。

我可能错过了枚举定义的任何考虑。

在我看来,这几乎没有提供:

var obj = Object.freeze({
    "RED":   0,
    "GREEN": 1,
    "BLUE":  2
});

您可以将其包装成一个函数,该函数可以在 ES5 之前的环境中工作,而不会冻结对象,例如:

function createEnum(spec) {
    if (Object.freeze) {
        spec = Object.freeze(spec);
    }
    return spec;
}

当然,如果您想要自动值,您可以增强它,例如:

function createEnum(spec) {
    var obj = {}, n;
    if (Object.prototype.toString.call(spec) === "[object Array]") { // No isArray pre ES5
        for (n = 0; n < spec.length; ++n) {
            if (spec[n] != null) { // checks for null or undefined
                obj[spec[n]] = n;
            }
        }
    }
    else {
        for (n in spec) {
            if (spec.hasOwnProperty(n)) {
                obj[n] = spec[n];
            }
        }
    }
    if (Object.freeze) {
        obj = Object.freeze(obj);
    }
    return obj;
}

如果你愿意,你可以把它放在Object不是 Object.prototype)上。


下面你说你不想使用freeze,因为它使对象不可扩展。很公平,以后想添加更多的枚举值。上面很容易适应这样做,如果存在则使用,Object.defineProperty如果不存在则仅分配属性。

于 2013-09-26T18:11:17.263 回答