【问题标题】:JavaScript, defining unmodifiable EnumerationsJavaScript,定义不可修改的枚举
【发布时间】:2013-09-26 18:04:10
【问题描述】:

因此,我受到这个问题 (Enums in 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. 我可能遗漏了 Enum 定义的任何注意事项。

jsFiddle:

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

【问题讨论】:

  • 这些“类型安全”如何?
  • Object.defineProperty 默认为不可写值。
  • @Duncan "Object.defineProperty 默认为不可写值" 好的,这与类型安全无关。它与不让枚举改变有关,是的,但是......
  • 检查 jsFiddle...它们不能被重写
  • 啊,是的……那里的术语有点混乱……已编辑。

标签: javascript enums unmodifiable


【解决方案1】:

旧版浏览器支持:因此,在未定义的地方重新定义 Object.defineProperty

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

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

我可能遗漏了 Enum 定义的任何注意事项。

在我看来,这提供的东西很少:

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,如果不存在则使用仅分配属性。

【讨论】:

  • Object.freeze 冻结对象,我所做的不是冻结对象,而是制作不可更改的属性...您仍然可以更改同一对象的其他属性...所以,您可以用枚举成员创建一个对象。
  • @Duncan:在同一个对象中混合枚举成员和非枚举成员听起来像是一个有问题的设计选择。但是,是的,freeze 会阻止您稍后向对象添加新的枚举值。
  • 此外,Enum 方法不会显示在对象的 for-each 循环中,因为它不是对象可枚举的一部分(未在 for-each 循环中列出)...每个 Enumator 定义on 一个对象将显示在该对象的 for-each 循环中,但是任何对单个属性的赋值尝试都会默默地失败,所以没有伤害,没有犯规。
猜你喜欢
  • 1970-01-01
  • 2013-01-08
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
相关资源
最近更新 更多