05. Property Attributes

Помимо имени и значения, свойства обладают атрибутами, определяющие их характеристики. Атрибуты, имеющиеся у всех свойств:

  • Признак доступности для перечисления (enumerable). Если true, то свойство просматривается в цикле for..in и методе Object.keys().

  • Признак доступности для настройки (configurable) контролирует попытки изменить другие атрибуты (а также определяет возможность удаления свойства).

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

    • Если true, то свойство можно удалять, а также менять его в дальнейшем при помощи новых вызовов defineProperty. Для такого свойства нельзя изменить его атрибуты configurable и enumerable, а так же нельзя изменить значение его атрибута writable с false на true, но его можно изменить с true на false.

  • Значение (value) - значение по ключу.

  • Признак доступности для записи (writable) контролирует попытки изменить атрибут value. Значение свойства можно менять, если true. По умолчанию false.

const c = { key: "value" };
Object.getOwnPropertyDescriptor(c, "key"); // => {value: "value", writable: true, enumerable: true, configurable: true}

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

Property attributes for get/set properties

В свойствах с методами доступа (get/set-функции) отсутствуют атрибуты value и writable: их доступность для записи определяется наличием или отсутствием метода записи. Поэтому четырьмя атрибутами свойств с методами доступа являются: метод чтения (get), метод записи (set), признак доступности для перечисления (enumerable) и признак доступности для настройки (configurable). Если свойство с методами доступа недоступно для настройки, нельзя изменить его методы чтения и записи и нельзя превратить его в простое свойство с данными.

Access to property attributes

Получить дескриптор свойства требуемого объекта можно вызовом Object.getOwnPropertyDescriptor(), который работает только с собственными свойствами. Чтобы получить атрибуты унаследованного свойства, необходимо явно выполнить обход цепочки прототипов.

Object.getOwnPropertyDescriptor({ x: 1 }, "x"); // => {value: 1, writable:true, enumerable:true, configurable:true}

Метод Object.getOwnPropertyDescriptors(obj) вернет объект с теми же ключами, а значениями будут дескрипторы свойств ключей объекта.

const obj = {
  get bar() {
    return "abc";
  }
};
console.log(Object.getOwnPropertyDescriptors(obj));

// Output:
// { [Symbol('foo')]:
//    { value: 123,
//      writable: true,
//      enumerable: true,
//      configurable: true },
//   bar:
//    { get: [Function: bar],
//      set: undefined,
//      enumerable: true,
//      configurable: true } }

Чтобы изменить значение атрибута свойства или создать новое свойство с заданными значениями атрибутов, следует вызвать метод Object.defineProperty(), передав ему объект, в котором требуется выполнить изменения, имя создаваемого или изменяемого свойства и объект дескриптора свойства. Дескриптор свойства, необязательно должен иметь все четыре атрибута.

const o = {};
Object.defineProperty(o, "x", {
  value: 1,
  writable: true,
  enumerable: false,
  configurable: true
});

Если возникнет необходимость создать или изменить сразу несколько свойств, можно воспользоваться методом Object.defineProperties(). Первым аргументом ему передается объект, который требуется изменить. Вторым аргументом – объект, отображающий имена создаваемых или модифицируемых свойств в дескрипторы этих свойств.

const p = Object.defineProperties(
  {},
  {
    x: { value: 1, writable: true, enumerable: true, configurable: true },
    y: { value: 1, writable: true, enumerable: true, configurable: true },
    r: {
      get: function() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
      },
      enumerable: true,
      configurable: true
    }
  }
);

Методы Object.defineProperty() и Object.defineProperties() возбуждают исключение TypeError, когда создание или изменение свойств запрещено. Например, при попытке добавить новое свойство в нерасширяемый объект.

Receipts

Примеры и паттерны использования:

Constant attribute

Object.defineProperty(user, "name", {
  value: "Anton",
  writable: false, // запретить присвоение "user.name="
  configurable: false // запретить удаление "delete user.name"
});

Non enumerable attribute

Object.defineProperty(user, "name", {
  value: "Anton",
  enumerable: false // запретить перебор свойства
});

Last updated