JavaScript. Подробное руководство, 6-е издание, стр. 135

<b>    var names; // Массив имен свойств</b>

<b>    if (arguments.length == 0) // Все собственные свойства объекта this</b>

<b>      names = Object.getOwnPropertyNames(this);</b>

<b>    else if (arguments.length == 1 &amp;&amp; Array.isArray(arguments[0]))</b>

<b>      names = arguments[0]; // Или массив указанных свойств </b>

<b>    else // Или имена в списке аргументов</b>

<b>      names = Array.prototype.splice.call(arguments, 0);</b>

<b>    // Вернуть новый объект Properties, представляющий указанные свойства return</b>

<b>    new Properties(this, names);</b>

<b>  }</b>

<b>  // Делает эту функцию новым, неперечислимым свойством Object.prototype.</b>

<b>  // Это единственное значение, экспортируемое из частной области видимости функции.</b>

<b>  Object.defineProperty(Object.prototype, &quot;properties&quot;, {</b>

<b>    value: properties,</b>

<b>    enumerable: false,</b>

<b>    writable: true,</b>

<b>    configurable: true</b>

<b>  });</b>

<b>  // Следующая функция-конструктор вызывается функцией properties().</b>

<b>  // Класс Properties представляет множество свойств объекта,</b>

<b>  function Properties(), names) {</b>

<b>    this.о = о; // Объект, которому принадлежат свойства</b>

<b>    this.names = names; // Имена свойств</b>

<b>  }</b>

<b>  // Делает неперечислимыми свойства, представленные объектом this</b>

<b>  Properties.prototype.hide = function() {</b>

<b>    var о = this.o, </b>
<b>hidden = { enumerable: false };</b>

<b>    this.names.forEach(function(n) {</b>

<b>                    if (o.hasOwnProperty(n))</b>

<b>                      Object.defineProperty(o, n, hidden);</b>

<b>    });</b>

<b>    return this;</b>

<b>  };</b>

<b>  // Делает свойства ненастраиваемыми и доступными только для чтения</b>

<b>  Properties.prototype.freeze = function() {</b>

<b>    var о = this.o, frozen = { writable: false, configurable: false };</b>

<b>    this.names.forEach(function(n) {</b>

<b>                if (o.hasOwnProperty(n))</b>

<b>                  Object.defineProperty(o, n, frozen);</b>

<b>    }):</b>

<b>    return this;</b>

<b>  };</b>

<b>  // Возвращает объект, отображающий имена свойств в дескрипторы.</b>

<b>  // Может использоваться для реализации копирования свойств вместе с их атрибутами:</b>

<b>  // Object.defineProperties(dest, src.properties().descriptors());</b>

<b>  Properties.prototype.descriptors = function() {</b>

<b>    var о = this.o, desc = {};</b>

<b>    this.names.forEach(function(n) {</b>

<b>               if (lo.hasOwnProperty(n)) return;</b>

<b>                 desc[n] = Object.getOwnPropertyDescriptor(o, n);</b>

<b>    });</b>

<b>    return desc;</b>

<b>  };</b>

<b>  // Возвращает отформатированный список свойств, в котором перечислены имена,</b>

<b>  // значения и атрибуты свойств. Термин &quot;permanent&quot; используется для обозначения</b>

<b>  // ненастраиваемых свойств, &quot;readonly&quot; - для обозначения свойств, не доступных</b>

<b>  // для записи, и &quot;hidden&quot; - для обозначения неперечислимых свойств.</b>

<b>  // Обычные перечислимые, доступные для записи и настраиваемые свойства</b>

<b>  // указываются в списке без атрибутов.</b>

<b>  Properties.prototype.toString = function() {</b>

<b>    var о = this.o; // Используется во вложенных функциях ниже</b>

<b>    var lines = this.names.map(nameToString);</b>

<b>    return &quot;{\n &quot; + lines.join(&quot;,\n &quot;) + &quot;\n}&quot;;</b>

<b>    function nameToString(n) {</b>

<b>      var s = desc = Object.getOwnPropertyDescriptor(o, n);</b>

<b>      if (!desc) return &quot;nonexistent &quot; + n + &quot;: undefined&quot;;</b>

<b>      if (!desc.configurable) s += &quot;permanent &quot;;</b>

<b>      if ((desc.get &amp;&amp; Idesc.set) || !desc.writable) s += &quot;readonly &quot;;</b>