Почему я могу установить [перечислимость и] возможность записи неконфигурируемых дескрипторов свойств? - PullRequest
6 голосов
/ 23 марта 2012

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 = false, for(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.

Почему я могу "понизить" дескрипторы, хотя они говорят, что они не настраиваются?

1 Ответ

16 голосов
/ 23 марта 2012

Во-первых, даже если 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, 
...