【问题标题】:Why can I set [enumerability and] writability of unconfigurable property descriptors?为什么我可以设置不可配置属性描述符的[可枚举性和]可写性?
【发布时间】:2012-03-22 20:16:22
【问题描述】:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty 状态:

可配置: 当且仅当此属性描述符的类型可以更改并且可以从相应对象中删除该属性时才为真。默认为false

所以,我有一个

var x = Object.defineProperty({}, "a", {
    value:true,
    writable:true,
    enumerable:true,
    configurable:false
});

现在我可以使用x.a = falsefor(i in x) 等。但即使描述符 is 应该是不可配置的,我也可以这样做

Object.defineProperty(x, "a", {writable:true}); // others defaulting to false
Object.defineProperty(x, "a", {}); // everything to false
Object.freeze(x); // does the same to the descriptors

反过来,再次将它们设置为 true,或者尝试定义访问器描述符,现在会引发错误。准确地说:Object.defineProperty: invalid modification of non-configurable property

为什么我可以“降级”描述符,尽管他们说它们是不可配置的?

【问题讨论】:

    标签: javascript ecmascript-5 defineproperty


    【解决方案1】:

    首先,即使configurablefalsewritable 也可以从true 更改为false。这是configurablefalse 时唯一允许的属性更改。允许这种转换是因为一些内置属性,包括(最显着)数组的length 属性(包括Array.prototype)被指定为writable: true, configurable: false。这是以前 ECMAScript 版本的遗产。如果configurable: false 阻止将writabletrue 更改为false,那么就不可能冻结数组。

    Object.defineProperty 不像你想象的那样工作。特别是,它处理属性描述符的方式会根据属性是否已经存在而有所不同。如果属性不存在,则描述符应该提供所有属性的定义,因此在使用描述符创建属性之前,描述符中任何缺失的属性都会被分配默认值。但是,对于已经存在的属性,描述符被视为属性当前属性设置的一组增量更改。描述符中未列出的属性不会更改。此外,在增量描述符中与当前属性属性值具有相同值的属性也被认为没有变化。所以以下都是合法的:

    Object.defineProperty(x, "a", {writable:false}); // can always change writable to false.
                                                    //others attributes, not changed
    Object.defineProperty(x, "a", {});     // no attributes, so nothing changes
    Object.freeze(x); // same as Object.defineProperty(x, "a", {writable:false});
    Object.defineProperty(x, "a", {enumerable:true, configurable: false}); //no change, 
    

    【讨论】:

    • 啊,谢谢你的解释。我以为我什至在我的一个测试中更改了不可配置属性的可枚举性(显式,而不是这些误导性的默认值),但我现在无法重现。
    • Object.freeze(x) 与将writable 设置为false 不同!它实际上是设置 writableconfigurable 来错误地渲染对象完全不可变(即变成一个常量)。
    • @Arijoon 这不是真的,根据the MDN docs for Object.freeze()。但是,freeze() 确实很浅。有关深度冻结功能的示例,请参阅这些文档。
    猜你喜欢
    • 2018-01-20
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2015-05-16
    • 1970-01-01
    相关资源
    最近更新 更多