为什么我可以设置不可配置属性描述符的[可枚举性和可写性]?

时间:2012-03-22 20:16:23

标签: javascript ecmascript-5 defineproperty

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

  

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

所以,我有一个

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

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

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

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

1 个答案:

答案 0 :(得分:16)

首先,即使configurablefalsewritable也可以从true更改为false。这是configurablefalse时允许的唯一属性更改。允许此转换是因为某些内置属性(包括(最值得注意的))数组的length属性(包括Array.prototype)被指定为writable: true, configurable: false。这是以前ECMAScript版本的遗产。如果configurable: false阻止将writabletrue更改为false,则无法冻结数组。

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

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,