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

9.8.6. Дескрипторы свойств

9.8.6. Дескрипторы свойств

В разделе 6.7 дается описание дескрипторов свойств, введенных стандартом ECMAScript 5, но там отсутствуют примеры, демонстрирующие различные случаи их использования. Мы завершим этот раздел, посвященный особенностям ECMAScript 5, расширенным примером, демонстрирующим многие операции со свойствами, допустимые в ECMAScript 5. Программный код в примере 9.23 добавляет в Object.prototype метод properties() (разумеется, недоступный для перечисления). Значение, возвращаемое этим методом, является объектом, представляющим список свойств и обладающим полезными методами для отображения свойств и атрибутов (которые могут пригодиться при отладке). Его можно использовать для получения дескрипторов свойств (на случай, если потребуется реализовать копирование свойств вместе с их атрибутами) и для установки атрибутов свойств (благодаря чему он может использоваться как альтернатива функциям hideProps() и freezeProps(), объявленным ранее). Этот единственный пример демонстрирует большинство особенностей свойств в ECMAScript 5, а также применение методики модульного программирования, о которой будет рассказываться в следующем разделе.

Пример 9.23. Особенности свойств в ECMAScript 5

/*
* Определяет метод properties() в Object.prototype, возвращающий объект, который
* представляет указанные свойства объекта, относительно которого был вызван метод
* (или все собственные свойства объекта, если метод был вызван без аргументов).
* Возвращаемый объект имеет четыре полезных метода:
* toString(), descriptors(), hide() и show().
*/
(function namespace() { // Обернуть все в частную область видимости функции
  // Эта функция будет превращена в метод всех объектов
  function properties() {
    var names; // Массив имен свойств
    if (arguments.length == 0) // Все собственные свойства объекта this
      names = Object.getOwnPropertyNames(this);
    else if (arguments.length == 1 && Array.isArray(arguments[0]))
      names = arguments[0]; // Или массив указанных свойств
    else // Или имена в списке аргументов
      names = Array.prototype.splice.call(arguments, 0);
    // Вернуть новый объект Properties, представляющий указанные свойства return
    new Properties(this, names);
  }
  // Делает эту функцию новым, неперечислимым свойством Object.prototype.
  // Это единственное значение, экспортируемое из частной области видимости функции.
  Object.defineProperty(Object.prototype, "properties", {
    value: properties,
    enumerable: false,
    writable: true,
    configurable: true
  });
  // Следующая функция-конструктор вызывается функцией properties().
  // Класс Properties представляет множество свойств объекта,
  function Properties(), names) {
    this.о = о; // Объект, которому принадлежат свойства
    this.names = names; // Имена свойств
  }
  // Делает неперечислимыми свойства, представленные объектом this
  Properties.prototype.hide = function() {
    var о = this.o, hidden = { enumerable: false };
    this.names.forEach(function(n) {
                    if (o.hasOwnProperty(n))
                      Object.defineProperty(o, n, hidden);
    });
    return this;
  };
  // Делает свойства ненастраиваемыми и доступными только для чтения
  Properties.prototype.freeze = function() {
    var о = this.o, frozen = { writable: false, configurable: false };
    this.names.forEach(function(n) {
                if (o.hasOwnProperty(n))
                  Object.defineProperty(o, n, frozen);
    }):
    return this;
  };
  // Возвращает объект, отображающий имена свойств в дескрипторы.
  // Может использоваться для реализации копирования свойств вместе с их атрибутами:
  // Object.defineProperties(dest, src.properties().descriptors());
  Properties.prototype.descriptors = function() {
    var о = this.o, desc = {};
    this.names.forEach(function(n) {
               if (lo.hasOwnProperty(n)) return;
                 desc[n] = Object.getOwnPropertyDescriptor(o, n);
    });
    return desc;
  };
  // Возвращает отформатированный список свойств, в котором перечислены имена,
  // значения и атрибуты свойств. Термин "permanent" используется для обозначения
  // ненастраиваемых свойств, "readonly" - для обозначения свойств, не доступных
  // для записи, и "hidden" - для обозначения неперечислимых свойств.
  // Обычные перечислимые, доступные для записи и настраиваемые свойства
  // указываются в списке без атрибутов.
  Properties.prototype.toString = function() {
    var о = this.o; // Используется во вложенных функциях ниже
    var lines = this.names.map(nameToString);
    return "{n " + lines.join(",n ") + "n}";
    function nameToString(n) {
      var s = desc = Object.getOwnPropertyDescriptor(o, n);
      if (!desc) return "nonexistent " + n + ": undefined";
      if (!desc.configurable) s += "permanent ";
      if ((desc.get && Idesc.set) || !desc.writable) s += "readonly ";
      if (!desc.enumerable) s += "hidden ";
      if (desc.get || desc.set)
        s += "accessor + n
      else
        s += n + ": " + ((typeof desc.value==="function")?"function"
                          :desc.value);
      return s;
    }
  };
  // Наконец, сделать методы экземпляров объекта-прототипа, объявленного
  // выше, неперечислимыми, с помощью методов, объявленных здесь.
  Properties.prototype.properties().hide();
}()); // Вызвать вмещающую функцию сразу после ее определения.

Оглавление книги


Генерация: 1.247. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз