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

Javascript 为什么我可以设置不可配置属性描述符的[可枚举性和]可写性?,javascript,ecmascript-5,defineproperty,Javascript,Ecmascript 5,Defineproperty,国家: 可配置: 当且仅当此属性描述符的类型可以更改,并且该属性可以从相应对象中删除时,为True。默认值为false 所以,我有一个 var x = Object.defineProperty({}, "a", { value:true, writable:true, enumerable:true, configurable:false }); 现在我可以使用x.a=false,for(I in x)等。但是即使描述符是不可配置的,我也可以这样做 Objec

国家:

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

所以,我有一个

var x = Object.defineProperty({}, "a", {
    value:true,
    writable:true,
    enumerable:true,
    configurable:false
});
现在我可以使用
x.a=false
for(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:对不可配置属性的修改无效


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

首先,即使
可配置的
假的
可写的
也可以从
真的
更改为
假的
。当
可配置
false
时,这是唯一允许的属性更改。之所以允许此转换,是因为一些内置属性,包括(最显著的)数组的
length
属性(包括
Array.prototype
)被指定为
可写:true,可配置:false
。这是以前ECMAScript版本的遗留版本。如果
configurable:false
阻止将
writable
true
更改为
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, 

啊,谢谢你的解释。我以为我甚至在一个测试中更改了不可配置属性的可枚举性(显式,不使用这些误导性的默认值),但我现在无法复制。
Object.freeze(x)
与将
writeable
设置为
false
不同!事实上,它将
可写
可配置
设置为false,从而使对象完全不可变(即变为常数)。@Arijoon说,这不是真的。然而,
freeze()
确实很肤浅;有关深度冻结功能的示例,请参见这些文档。