Descriptores de propiedades

Es probable que la mayor parte de tu interacción con las propiedades del objeto se realice a nivel de la superficie, lo que incluye la creación de literales de objetos, la configuración y el acceso los valores de las propiedades con claves. Sin embargo, puedes configurar de forma interna cualquier propiedad de un objeto para un control detallado sobre cómo se accede a esas propiedades alterados y definidos. Cada propiedad de objeto tiene un conjunto de atributos invisibles que contienen metadatos asociados con esa propiedad, llamada "propiedad descriptores”.

Hay dos tipos de descriptores asociados con cualquier propiedad: descriptores de datos y descriptores de accesos. Un descriptor de datos incluye pares clave-valor que contienen el valor de una propiedad, sin importar si valor es grabable, configurable o enumerable. Los descriptores de acceso contienen que se ejecutan cuando se configura, cambia o accede a una propiedad.

Propiedad Tipo de descriptor Valor predeterminado de
Object.defineProperty()
Descripción
[[Value]] Datos undefined Contiene el valor de una propiedad.
[[Writable]] Datos false Determina si puedes cambiar el valor de la propiedad.
[[Get]] Acceso undefined La función get de la propiedad, que se ejecuta cuando el valor se accede a ella.
[[Set]] Acceso undefined La función set de la propiedad, que se ejecuta cuando el valor se configura o cambia la propiedad.
[[Configurable]] Ambos false Si es false, la propiedad no se puede borrar y su no se pueden cambiar. Si es false y [[Writable]] es true, el valor de la propiedad puede aún se modifiquen.
[[Enumerable]] Ambos false Si es true, puedes iterar en la propiedad con Bucles for...in o la estática Object.keys() .

Cada una de estas propiedades usa la misma abreviatura que [[Prototype]], lo que indica de que no se puede acceder a estas propiedades directamente. En su lugar, usa el El método estático Object.defineProperty() para definir o modificar las propiedades de un . Object.defineProperty() acepta tres argumentos: el objeto sobre el que se debe actuar, la clave de propiedad que se creará o modificará y un objeto que contenga el descriptores asociados con la propiedad que se crea o modifica.

De forma predeterminada, las propiedades creadas con Object.defineProperty() no se pueden escribir, enumerar ni configurar. Sin embargo, cualquier propiedad que crees ya sea como parte del literal del objeto o con la notación de puntos o corchetes que admiten escritura, que se pueden enumerar y configurar.

const myObj = {};

Object.defineProperty(myObj, 'myProperty', {
  value
: true,
  writable
: false
});

myObj
.myProperty;
> true

myObj
.myProperty = false;

myObj
.myProperty;
> true

Por ejemplo, cuando [[Writable]] tiene un valor false, intenta establecer un valor nuevo. de la propiedad asociada falla silenciosamente fuera del modo estricto y arroja un en el modo estricto:

{
   
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

El uso eficaz de los descriptores es un concepto bastante avanzado, pero comprender la estructura interna de un objeto es esencial para entender las sintaxis involucradas en el trabajo con objetos de formas más comunes. Por ejemplo: estos conceptos entran en juego cuando se usa el método estático Object.create(), lo que te brinda un control detallado sobre cualquier prototipo adjunto al nuevo .

Object.create() crea un objeto nuevo con un objeto existente como su para crear un prototipo. Esto permite que el nuevo objeto herede propiedades y métodos de otro definido por el usuario de la misma forma en que los objetos heredan propiedades de Prototipo Object integrado de JavaScript. Cuando invocas Object.create() con un objeto como argumento, se crea un objeto vacío con el objeto pasado como su prototipo.

const myCustomPrototype = {
 
'myInheritedProp': 10
};

const newObject = Object.create( myCustomPrototype );

newObject
;
> Object {  }
<prototype>: Object { myInheritedProp: 10 }
  myInheritedProp
: 10
 
<prototype>: Object { }

Object.create puede tomar un segundo argumento que especifique propiedades propias para la un objeto recién creado con una sintaxis similar a Object.defineProperty(), es decir, un objeto que asigna claves a un conjunto de atributos del descriptor:

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 }

En este ejemplo, el objeto nuevo (myObj) usa un literal de objeto (myCustomPrototype) como prototipo, que, a su vez, contiene el prototipo Object.prototype, lo que da como resultado una serie de prototipos heredados llamados cadena de prototipos. Cada objeto tiene un prototipo, ya sea asignado o heredado, que tiene un prototipo propio asignado o heredado. Esta cadena termina en un Prototipo null, que no tiene ningún prototipo propio.

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 { }

Las propiedades contenidas en el prototipo de un valor están disponibles en el "nivel superior". de un objeto, sin la necesidad de acceder directamente a la propiedad del prototipo:

const objectLiteral = {
   
"value" : true
};

objectLiteral
;
> Object { value: true }
    value
: true
   
<prototype>: Object { }

objectLiteral
.toString();
"[object Object]"

Este patrón se aplica a toda la cadena de prototipos asociada con un Cuando intenta acceder a una propiedad, el intérprete busca esa propiedad de cada "nivel" de la cadena del prototipo, de arriba abajo, hasta que encuentra la propiedad o la cadena finaliza:

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."

Verifica tus conocimientos

¿Qué descriptores son descriptores de acceso?

[[Writable]]
[[Get]]
[[Set]]