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

Why can I set [enumerability and] writability of unconfigurable property descriptors?

本文关键字:枚举 设置 我可以 可确定 描述 属性 为什么      更新时间:2023-09-26

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

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

首先,即使configurablefalsewritable也可以从true更改为false。当configurablefalse时,这是唯一允许的属性更改。允许这种转换是因为一些内置属性,包括(最显著的)数组(包括Array.prototype)的length属性,被指定为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,