Большая часть вашего взаимодействия со свойствами объекта, скорее всего, будет осуществляться на поверхностном уровне, включая создание литералов объекта, а также установку значений свойств и доступ к ним с помощью ключей. Однако вы можете внутренне настроить любое свойство объекта для детального контроля над тем, как эти свойства доступны, изменяются и определяются. Каждое свойство объекта имеет набор невидимых атрибутов, содержащих метаданные, связанные с этим свойством, называемые «дескрипторами свойств».
Существует два типа дескрипторов, связанных с любым свойством: дескрипторы данных и дескрипторы средств доступа . Дескриптор данных включает пары ключ-значение, которые содержат значение свойства, независимо от того, является ли это значение доступным для записи, настраиваемым или перечислимым. Дескрипторы средств доступа содержат функции, которые выполняются при установке, изменении или доступе к свойству.
| Свойство | Тип дескриптора |  Значение по умолчанию отObject.defineProperty() | Описание | 
|---|---|---|---|
 [[Value]] | Данные |  undefined | Содержит значение свойства. | 
 [[Writable]] | Данные |  false | Определяет, можете ли вы изменить значение свойства. | 
 [[Get]] | Аксессор |  undefined | Функция получения свойства, которая выполняется при доступе к свойству. | 
 [[Set]] | Аксессор |  undefined | Функция установки свойства, которая выполняется, когда свойство устанавливается или изменяется. | 
 [[Configurable]] | Оба |  false |  Если это значение false , свойство нельзя удалить и его атрибуты нельзя изменить. Если это значение false и [[Writable]] имеет true , значение свойства все равно можно изменить. | 
 [[Enumerable]] | Оба |  false |  Если это true , вы можете перебирать свойство, используя циклы for...in или статический метод Object.keys() . | 
 Каждое из этих свойств использует то же сокращение, что и [[Prototype]] , что указывает на то, что эти свойства не предназначены для прямого доступа. Вместо этого используйте статический метод Object.defineProperty() для определения или изменения свойств объекта. Object.defineProperty() принимает три аргумента: объект, над которым нужно действовать, ключ свойства, который нужно создать или изменить, и объект, содержащий дескрипторы, связанные с создаваемым или изменяемым свойством.
 По умолчанию свойства, созданные с помощью Object.defineProperty() недоступны для записи, перечисления или настройки. Однако любое свойство, которое вы создаете либо как часть литерала объекта, либо с использованием записи через точку или скобку, доступно для записи, перечисления и настройки.
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
  value: true,
  writable: false
});
myObj.myProperty;
> true
myObj.myProperty = false;
myObj.myProperty;
> true
 Например, когда [[Writable]] имеет false значение, попытка установить новое значение для связанного свойства терпит неудачу вне строгого режима и выдает ошибку в строгом режиме :
{
    const myObj = {};
    Object.defineProperty(myObj, 'myProperty', {
    value: true,
    writable: false
    });
    myObj.myProperty = false;
    myObj.myProperty;
}
> true
(function () {
    "use strict";
    const myObj = {};
    Object.defineProperty(myObj, 'myProperty', {
    value: true,
    writable: false
    });
    myObj.myProperty = false;
    myObj.myProperty;
}());\
> Uncaught TypeError: "myProperty" is read-only
 Эффективное использование дескрипторов — довольно сложная концепция, но понимание внутренней структуры объекта необходимо для понимания синтаксиса, используемого при работе с объектами более распространенными способами. Например, эти концепции вступают в силу при использовании статического метода Object.create() , который дает вам детальный контроль над любыми прототипами, прикрепленными к новому объекту.
 Object.create() создает новый объект, используя существующий объект в качестве прототипа. Это позволяет новому объекту наследовать свойства и методы от другого пользовательского объекта так же, как объекты наследуют свойства от встроенного в JavaScript прототипа Object . Когда вы вызываете Object.create() с объектом в качестве аргумента, он создает пустой объект с переданным объектом в качестве его прототипа.
const myCustomPrototype = {
  'myInheritedProp': 10
};
const newObject = Object.create( myCustomPrototype );
newObject;
> Object {  }
<prototype>: Object { myInheritedProp: 10 }
  myInheritedProp: 10
  <prototype>: Object { … }
 Object.create может принимать второй аргумент, определяющий собственные свойства для вновь созданного объекта, используя синтаксис, аналогичный Object.defineProperty() — то есть ключи сопоставления объекта с набором атрибутов дескриптора:
const myCustomPrototype = {
  'myInheritedProp': 10
};
const myObj = Object.create( myCustomPrototype, {
        myProperty: {
            value: "The new property value.",
            writable: true,
            configurable: true
        }
  });
myObj;
> Object { … }
    myProperty: "The new property value."
    <prototype>: Object { myInheritedProp: 10 }
 В этом примере новый объект ( myObj ) использует литерал объекта ( myCustomPrototype ) в качестве прототипа, который сам содержит унаследованный Object.prototype , в результате чего образуется серия унаследованных прототипов, называемая цепочкой прототипов . У каждого объекта есть прототип, назначенный или унаследованный, который имеет собственный назначенный или унаследованный прототип. Эта цепочка заканчивается null прототипом, который не имеет собственного прототипа.
const myPrototype = {
  'protoProp': 10
};
const newObject = Object.setPrototypeOf( { 'objProp' : true }, myPrototype );
newObject;
> Object { objProp: true }
    objProp: true
    <prototype>: Object { protoProp: 10 }
        protoProp: 10
        <prototype>: Object { … }
Свойства, содержащиеся в прототипе значения, доступны на «верхнем уровне» объекта без необходимости прямого доступа к свойству прототипа:
const objectLiteral = {
    "value" : true
};
objectLiteral;
> Object { value: true }
    value: true
    <prototype>: Object { … }
objectLiteral.toString();
"[object Object]"
Этот шаблон справедлив для всей цепочки прототипов, связанной с объектом: при попытке доступа к свойству интерпретатор ищет это свойство на каждом «уровне» цепочки прототипов сверху вниз, пока не найдет свойство или цепочку. заканчивается:
const myCustomPrototype = {
  'protoProp': "Prototype property value."
};
const myObj = Object.create( myCustomPrototype, {
    myProperty: {
        value: "Top-level property value.",
        writable: true,
        configurable: true
    }
});
myObj.protoProp;
> "Prototype property value."
Проверьте свое понимание
Какие дескрипторы являются аксессорами?
[[Get]][[Set]][[Writable]]