JavaScript. Подробное руководство, 6-е издание, стр. 131
<b> function idGetter() { // Функция чтения, возвращающая id</b><b> if (!(idprop in this)) { // Если объект еще не имеет id</b><b> if (!Object.isExtensible(this)) // И если можно добавить свойство</b><b> throw Error("Нельзя определить id нерасширяемого объекта”);</b><b> Object.defineProperty(this, idprop, { // Добавить его.</b><b> value: nextid++, // Значение</b><b> writable: false, // Только для чтения </b><b> enumerable: false, // Неперечислимое</b><b> configurable: false // Неудаляемое</b><b> }):</b><b> }</b><b> return this[idprop]; // Вернуть существующее или новое значение</b><b> };</b><b> // Следующие переменные используются функцией idGetter() и являются</b><b> // частными для этой функции</b><b> var idprop = "|**objectId**|"; // Предполагается, что это свойство</b><b> // больше нигде не используется </b><b> var nextid = 1; // Начальное значение для id</b><b>}()); // Вызвать функцию-обертку, чтобы выполнить программный код</b>9.8.2. Определение неизменяемых классов
Помимо возможности делать свойства неперечислимыми, стандарт ECMAScript 5 позволяет делать свойства доступными только для чтения, что может быть довольно удобно при создании классов, экземпляры которых не должны изменяться. В примере 9.18 приводится неизменяемая версия класса
<b>Range</b><b>Object.defineProperties()</b><b>Object.create().</b><b>Object.defineProperties()</b><b>new</b>Пример 9.18. Неизменяемый класс со свойствами и методами, доступными только для чтения
<b>// Эта функция может работать и без ключевого слова 'new': она одновременно</b><b>// является и конструктором, и фабричной функцией </b><b>function Range(from,to) {</b><b> // Дескрипторы свойств from и to, доступных только для чтения,</b><b> var props = {</b><b> from: {value:from, enumerable:true,writable:false,configurable:false},</b><b> to: {value:to, enumerable:true, writable:false, configurable:false}</b><b> };</b><b> if (this instanceof Range) // Если вызвана как конструктор</b><b> Object.defineProperties(this, props): // Определить свойства</b><b> else // Иначе как фабричная функция</b><b> return Object.create(Range.prototype, // Создать и вернуть новый</b><b> props): // объект Range со свойствами</b><b>}</b><b>// Если добавлять свойства в объект Range.prototype тем же способом, можно будет</b><b>// определить атрибуты этих свойств. Поскольку мы не указываем атрибуты enumerable,</b><b>// writable и configurable, они по умолчанию получают значение false.</b><b>Object.defineProperties(Range.prototype, { </b><b> includes: {</b><b> value: function(x) { return this.from <= x && x <= this.to: }</b><b> ),</b><b> foreach: {</b><b> value: function(f) {</b><b> for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);</b><b> }</b><b> },</b><b> toString: {</b><b> value: function() { return "(” + this, from + "..." + this, to + }</b><b> }</b><b>});</b>Для определения неизменяемых и неперечислимых свойств в примере 9.18 используются функции
<b>Object.defineProperties()</b><b>Object.create().</b>Пример 9.19/ Вспомогательные функции для работы с дескрипторами свойств
<b>// Делает указанные (или все) свойства объекта о </b><b>// недоступным для записи и настройки,</b><b>function freezeProps(o) {</b>