Методы получения и записи значений атрибутов свойств, предусмотренные стандартом ECMAScript 5, используют объект, называемый дескриптором свойства (
<b>property descriptor</b>
), представляющий множество из четырех атрибутов. Объект дескриптора свойства обладает свойствами, имена которых совпадают с именами атрибутов свойства, которое он описывает. То есть объекты-дескрипторы свойств с данными имеют свойства с именами
<b>value</b>
,
<b>writable</b>
,
<b>enumerable</b>
и
<b>configurable</b>
. А дескрипторы свойств с методами доступа вместо свойств
<b>value</b>
и
<b>writable</b>
имеют свойства
<b>get</b>
и
<b>set</b>
. Свойства
<b>writable</b>
,
<b>enumerable</b>
и
<b>configurable</b>
являются логическими значениями, а свойства
<b>get</b>
и
<b>set</b>
- функциями.
Получить дескриптор свойства требуемого объекта можно вызовом
<b>Object.get-OwnPropertyDescriptor():</b>
<b>// Вернет {value: 1, writable:true, enumerable:true, configurable:true}</b>
<b>Object.getOwnPropertyDescriptor({x:1}, "x");</b>
<b>// Теперь получим свойство octet объекта random, объявленного выше.</b>
<b>// Вернет { get: /*func*/. set:undefined, enumerable:true, configurable:true}</b>
<b>Object.getOwnPropertyDescriptor(random, "octet");</b>
<b>// Вернет undefined для унаследованных и несуществующих свойств. </b>
<b>Object.getOwnPropertyDescriptor({}, "х"); // undefined, нет такого свойства</b>
<b>Object.getOwnPropertyDescriptor({}, "toString"); // undefined, унаследованное</b>
Как можно заключить из названия метода,
<b>Object.getOwnPropertyDescriptor()</b>
работает только с собственными свойствами. Чтобы получить атрибуты унаследованного свойства, необходимо явно выполнить обход цепочки прототипов (смотрите описание
<b>Object.getPrototypeOf()</b>
в разделе 6.8.1).
Чтобы изменить значение атрибута свойства или создать новое свойство с заданными значениями атрибутов, следует вызвать метод
<b>Object.defineProperty()</b>
, передав ему объект, в котором требуется выполнить изменения, имя создаваемого или изменяемого свойства и объект дескриптора свойства:
<b>var о = {}; // Создать пустой объект без свойств</b>
<b>// Создать неперечислимое простое свойство х со значением 1.</b>
<b>Object.defineProperty(o, "х", { value : 1,</b>
<b> writable: true, enumerable: false, configurable: true}):</b>
<b>// Убедиться, что свойство создано и является неперечислимым </b>
<b>о.х; // => 1</b>
<b>Object.keys(o) // => []</b>
<b>// Теперь сделать свойство х доступным только для чтения </b>
<b>Object.defineProperty(o, "х", { writable: false });</b>
<b>// Попытаться изменить значение свойства</b>
<b>о.х = 2; // Неудача, в строгом режиме возбудит ТуреЕrror</b>
Дескриптор свойства, передаваемый методу
<b>Object.defineProperty(),</b>
необязательно должен иметь все четыре атрибута. При создании нового свойства отсутствующие атрибуты получат значение
<b>false</b>
или
<b>undefined</b>
. При изменении существующего свойства для отсутствующих атрибутов будут сохранены текущие значения. Обратите внимание, что этот метод изменяет существующее собственное свойство или создает новое собственное свойство - он не изменяет унаследованные свойства.
Если возникнет необходимость создать или изменить сразу несколько свойств, можно воспользоваться методом
<b>Object.defineProperties().</b>
Первым аргументом ему передается объект, который требуется изменить. Вторым аргументом - объект, отображающий имена создаваемых или модифицируемых свойств в дескрипторы этих свойств. Например:
<b>var р = Object.defineProperties({},{</b>
<b> х:{ </b>
<b> value: 1, </b>
<b> writable: true,</b>
<b> enumerable:true, </b>
<b> configurable:true </b>
<b> }, </b>
<b> y:{ </b>
<b> value: 1,</b>
<b> writable: true,</b>
<b> enumerable:true,</b>
<b> configurable:true },</b>
<b> r:{</b>
<b> get: function() { return Math.sqrt(this.x*this.x + this.y*this.y) },</b>
<b> enumerable:true,</b>
<b> configurable:true</b>
<b> }</b>
<b>});</b>
В этом примере все начинается с пустого объекта, в который затем добавляются два свойства с данными и одно свойство с методами доступа, доступное только для чтения. Он опирается на тот факт, что
<b>Object.defineProperties()</b>
возвращает модифицированный объект (подобно методу
<b>Object.defineProperty()</b>
).