Выбрать главу

• Если свойство недоступно для настройки, нельзя изменить его атрибуты configurable и enumerable.

• Если свойство с методами доступа недоступно для настройки, нельзя изменить его методы чтения и записи и нельзя превратить его в простое свойство с данными.

• Если свойство с данными недоступно для настройки, нельзя превратить его в свойство с методами доступа.

• Если свойство с данными недоступно для настройки, нельзя изменить значение его атрибута writable с false на true, но его можно Изменить с true на false.

• Если свойство с данными недоступно для настройки и для записи, нельзя изменить его значение. Однако изменить значение свойства, недоступного для записи можно, если оно доступно для настройки (потому что свойство можно сделать доступным для записи, изменить его значение и затем опять сделать свойство доступным только для чтения).

Пример 6.2 включает функцию extend(), которая копирует свойства из одного объекта в другой. Эта функция просто копирует имена и значения свойств и игнорирует их атрибуты. Кроме того, она не копирует методы чтения и записи из свойств с методами доступа, а просто преобразует их в свойства со статическими данными. В примере 6.3 показана новая версия extend(), которая копирует все атрибуты свойств с помощью Object.getOwnPropertyDescriptor() и Object.defineProperty(). Но на этот раз данная версия оформлена не как функция, а как новый метод объекта и добавляется в Object.prototype как свойство, недоступное для перечисления.

Пример 6.3. Копирование атрибутов свойств

/*

* Добавляет неперечислимый метод extend() в Object.prototype.

* Этот метод расширяет объекты возможностью копирования свойств из объекта,

* переданного в аргументе. Этот метод копирует не только значение свойств,

* но и все их атрибуты. Из объекта в аргументе копируются все собственные

* свойства (даже недоступные для перечисления), за исключением одноименных

* свойств, имеющихся в текущем объекте.

*/

Object.defineProperty(Object.prototype,

  "extend", // Определяется Object.prototype.extend

  {

    writable: true,

    enumerable: false, // Сделать неперечислимым

    configurable: true,

    value: function(o) { // Значением свойства является данная функция

    // Получить все собственные свойства, даже неперечислимые

    var names = Object.getOwnPropertyNames(o);

    // Обойти их в цикле

    for(var і = 0: і < names.length; i++) {

      // Пропустить свойства, уже имеющиеся в данном объекте

      if (names[i] in this) continue;

      // Получить дескриптор свойства из о

      var desc = Object.getOwnPropertyDescriptor(o,names[i]);

      // Создать с его помощью свойство в данном объекте

      Object.defineProperty(this, names[i], desc);

    }

  }

});

6.7.1. Устаревшие приемы работы с методами чтения и записи

Синтаксис определения свойств с методами доступа в литералах объектов, описанный разделе 6.6, позволяет определять свойства с методами в новых объектах, но, он не дает возможности получать методы чтения и записи и добавлять новые свойства с методами доступа к существующим объектам. В ECMAScript 5 для этих целей можно использовать Object.getOwnPropertyDescriptor() и Object.defineProperty().

Большинство реализаций JavaScript (за исключением веб-броузера IE) поддерживали синтаксис get и set в литералах объектов еще до принятия стандарта ECMAScript 5. Эти реализации поддерживают нестандартный, устаревший API для получения и назначения методов чтения и записи. Этот API состоит из четырех методов, доступных во всех объектах. __lookupGetter__() и __lookupSetter__() возвращают методы чтения и записи для указанного свойства. А методы __defineGetter__() и __defineSetter__() позволяют определить метод чтения или записи:

в первом аргументе они принимают имя свойства, а во втором - метод чтения или записи. Имена всех этих методов начинаются и оканчиваются двумя символами подчеркивания, чтобы показать, что они являются нестандартными методами. Эти нестандартные методы не описываются в справочном разделе.