Во-первых, даже если configurable
равно false
, writable
можно изменить с true
на false
. Это единственное допустимое изменение атрибута, когда configurable
равно false
. Этот переход был разрешен, потому что некоторые встроенные свойства, включая (в особенности) свойство length
массивов (включая Array.prototype
), определены как writable: true, configurable: false
. Это наследие предыдущих версий ECMAScript. Если configurable: false
помешает изменить writable
с true
на 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,