# 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`.

```javascript
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()`, который работает только с собственными свойствами. Чтобы получить атрибуты унаследованного свойства, необходимо явно выполнить обход цепочки прототипов.

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

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

```javascript
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()`, передав ему объект, в котором требуется выполнить изменения, имя создаваемого или изменяемого свойства и объект дескриптора свойства. Дескриптор свойства, необязательно должен иметь все четыре атрибута.

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

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

```javascript
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

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

### Non enumerable attribute

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://strctr.gitbook.io/programming/01-languages/javascript/01-language/b-structured/b2-objects/05-property-attributes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
