JavaScript. Подробное руководство, 6-е издание, стр. 132
<b> var props = (arguments.length == 1) // Если один аргумент,</b><b> ? Object.getOwnPropertyNames(o) // изменить все свойства,</b><b> : Array.prototype.splice.call(arguments, 1);</b><b> // иначе только указанные</b><b> props.forEach(function(n) { // Делает каждое свойство ненастраиваемым</b><b> // и доступным только для чтения</b><b> // Пропустить ненастраиваемые свойства</b><b> if (!Object.getOwnPropertyDescriptor(o,n).configurable) return:</b><b> Object.defineProperty(o, n, { writable: false, configurable: false });</b><b> }):</b><b> return о; // Чтобы можно было продолжить работу с объектом о</b><b>}</b><b>// Делает неперечислимыми указанные (или все) свойства объекта о,</b><b>// если они доступны для настройки,</b><b>function hideProps(o) {</b><b> var props = (arguments.length == 1) // Если один аргумент,</b><b> ? Object.getOwnPropertyNames(o) // изменить все свойства,</b><b> : Array.prototype.splice.call(arguments, 1);</b><b> // иначе только указанные</b><b> props.forEach(function(n) { // Скрыть каждое от цикла for/in</b><b> // Пропустить ненастраиваемые свойства</b><b> if (!Object.getOwnPropertyDescriptor(o,n).configurable) return:</b><b> Object.defineProperty(o, n, { enumerable: false });</b><b> }):</b><b> return o;</b><b>}</b>Функции
<b>Object.defineProperty()</b><b>Object.defineProperties()</b><b>false</b><b>hideProps()</b><b>enumerable</b>С помощью этих двух функций можно писать определения классов с использованием преимуществ ECMAScript 5, без существенного изменения привычного стиля определения классов. В примере 9.20 приводится определение неизменяемого класса
<b>Range</b>Пример 9.20. Более простое определение неизменяемого класса
<b>function Range(from, to) { // Конструктор неизменяемого класса Range</b><b> this.from = from;</b><b> this.to = to;</b><b> freezeProps(this); // Сделать свойства неизменяемыми</b><b>}</b><b>Range.prototype = hideProps({ // Определить неперечислимые свойства прототипа</b><b> constructor: Range,</b><b> includes: function(x) { return this.from <= x && x <= this.to; },</b><b> foreach: function(f) {for(var x=Math.ceil(this.from);x<=this.to;x++) f(x);},</b><b> toString: function() { return "(" + this.from + "..." + this.to + ")"; }</b><b>});</b>9.8.3. Сокрытие данных объекта
В разделе 9.6.6 и в примере 9.10 было показано, как можно использовать переменные и аргументы функции-конструктора для сокрытия данных объекта, создаваемого этим конструктором. Недостаток этого приема заключается в том, что в ECMAScript 3 допускается возможность замещения методов доступа к этим данным. Стандарт ECMAScript 5 позволяет обеспечить более надежное сокрытие частных данных за счет определения методов доступа к свойствам, которые не могут быть удалены. Этот способ демонстрируется в примере 9.21.
Пример 9.21. Класс Range со строго инкапсулированными границами
<b>// Эта версия класса Range является изменяемой, но она следит за своими</b><b>// границами, обеспечивая выполнение условия from <= to.</b><b>function Range(from, to) {</b><b> // Проверить соблюдение условия при создании</b><b> if (from > to) throw new Error("Range: значение from должно быть <= to");</b><b> // Определение методов доступа, которые следят за соблюдением условия</b><b> function getFrom() { return from; }</b><b> function getTo() { return to; }</b><b> function setFrom(f) { // He позволяет устанавливать значение from > to</b><b> if (f <= to) from = f;</b><b> else throw new Error("Range: значение from должно быть <= to");</b><b> }</b><b> function setTo(t) { // He позволяет устанавливать значение to < from</b><b> if (t >= from) to = t;</b><b> else throw new Error("Range: значение to должно быть >= from");</b>