Descripteurs de propriété

La majeure partie de votre interaction avec les propriétés des objets y compris la création de littéraux d'objets, la définition à l'aide de clés. Cependant, vous pouvez configurer en interne n'importe quelle propriété de un objet pour contrôler précisément l'accès à ces propriétés, modifiées et définies. Chaque propriété d'objet possède un ensemble d'attributs invisibles contenant les métadonnées associées à cette propriété, appelée "propriété de description. »

Deux types de descripteurs sont associés à chaque propriété: descripteurs de données et descripteurs d'accès. Un descripteur de données comprend des paires clé/valeur contenant la valeur d'une propriété, que cette propriété la valeur est accessible en écriture, configurable ou énumérable. Les descripteurs d'accesseur contiennent fonctions qui s'exécutent lorsqu'une propriété est définie, modifiée ou consultée.

Propriété Type de descripteur Valeur par défaut de
Object.defineProperty()
Description
[[Value]] Données undefined Contient la valeur d'une propriété.
[[Writable]] Données false Détermine si vous pouvez modifier la valeur de la propriété.
[[Get]] Accesseur undefined La fonction getter de la propriété, qui s'exécute lorsque la est accessible.
[[Set]] Accesseur undefined La fonction setter de la propriété, qui s'exécute lorsque la propriété est définie ou modifiée.
[[Configurable]] Les deux false Si la valeur est false, la propriété ne peut pas être supprimée et ses ne peuvent pas être modifiés. S'il s'agit de false et [[Writable]] est true, la valeur de la propriété peut restent inchangées.
[[Enumerable]] Les deux false Si la valeur est true, vous pouvez itérer la propriété en utilisant Boucles for...in ou Object.keys() statique .

Chacune de ces propriétés utilise le même raccourci que [[Prototype]], ce qui indique que ces propriétés ne sont pas destinées à être accessibles directement. Utilisez plutôt la méthode Object.defineProperty() pour définir ou modifier les propriétés d'une . Object.defineProperty() accepte trois arguments: l'objet sur lequel agir, la clé de la propriété à créer ou à modifier, ainsi qu'un objet contenant la descripteurs associés à la propriété en cours de création ou de modification.

Par défaut, les propriétés créées avec Object.defineProperty() ne sont ni accessibles en écriture, ni énumération, ni configurables. Cependant, toute propriété que vous créez soit dans le littéral d'objet, soit en utilisant la notation par points ou accolades, accessible en écriture, énumérable et configurable.

const myObj = {};

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

myObj.myProperty;
> true

myObj.myProperty = false;

myObj.myProperty;
> true

Par exemple, lorsque [[Writable]] a une valeur false, essayer de définir une nouvelle valeur pour la propriété associée échoue silencieusement en dehors du mode strict et génère une erreur en mode strict:

{
    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

L'utilisation efficace des descripteurs est un concept assez avancé, mais comprendre la structure interne d’un objet est essentiel pour comprendre les syntaxes impliquées dans l’utilisation d’objets de manière plus courante. Par exemple : ces concepts entrent en jeu lorsque vous utilisez la méthode statique Object.create(), ce qui vous permet de contrôler précisément les prototypes attachés au nouveau .

Object.create() crée un objet en utilisant un objet existant comme son un prototype. Cela permet au nouvel objet d'hériter des propriétés et méthodes d'un autre défini par l'utilisateur de la même manière que les objets héritent des propriétés Prototype Object intégré de JavaScript. Lorsque vous appelez Object.create() avec un objet en tant qu'argument, un objet vide est créé, l'objet transmis étant son prototype.

const myCustomPrototype = {
  'myInheritedProp': 10
};

const newObject = Object.create( myCustomPrototype );

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

Object.create peut utiliser un second argument spécifiant ses propres propriétés pour la fonction objet que vous venez de créer à l'aide d'une syntaxe semblable à Object.defineProperty(), Autrement dit, un objet mappant des clés à un ensemble d'attributs de descripteurs:

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 }

Dans cet exemple, le nouvel objet (myObj) utilise un littéral d'objet (myCustomPrototype) comme prototype, qui contient elle-même les données héritées Object.prototype. Il en résulte une série de prototypes hérités, appelés les chaîne de prototypes. Chaque objet possède un prototype, qu'il soit attribué ou hérité, qui possède son propre prototype attribué ou hérité. Cette chaîne se termine à un null, qui n'a pas de prototype qui lui est propre.

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

Les propriétés contenues dans le prototype d'une valeur sont disponibles au "niveau supérieur" d'un objet, sans avoir à accéder directement à la propriété du prototype:

const objectLiteral = {
    "value" : true
};

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

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

Ce modèle est valable pour l'ensemble de la chaîne de prototypes associée à objet: lorsqu'il tente d'accéder à une propriété, l'interprète la recherche. propriété à chaque "niveau" de la chaîne prototype, de haut en bas, jusqu'à ce qu'elle trouve la propriété ou la fin de la chaîne:

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

Testez vos connaissances

Quels descripteurs sont des accesseurs ?

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