--- title: Métaprogrammation slug: Web/JavaScript/Guide/Meta_programming tags: - Guide - JavaScript - Proxy - Reflect translation_of: Web/JavaScript/Guide/Meta_programming original_slug: Web/JavaScript/Guide/Métaprogrammation --- {{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/iterateurs_et_generateurs","Web/JavaScript/Guide/Modules")}} À partir d'ECMAScript 2015, JavaScript fournit les objets natifs {{jsxref("Proxy")}} et {{jsxref("Reflect")}}. Ces objets permettent d'intercepter et de définir des comportements spécifiques pour certaines opérations fondamentales du langage (par exemple la recherche d'une propriété, l'affectation, l'énumération, l'appel d'une fonction, etc.). Grâce à ces deux objets, il est possible d'interagir avec le langage lui-même (on parle alors de métaprogrammation). ## Les proxies Introduits avec ECMAScript 2015, les objets {{jsxref("Proxy")}} permettent d'intercepter certaines opérations JavaScript et de définir le comportement à avoir quand celles-ci se produisent. Par exemple, on peut intercepter l'accès à une propriété d'un objet : ```js var handler = { get: function(cible, nom){ return nom in cible ? cible[nom] : 42; }}; var p = new Proxy({}, handler); p.a = 1; console.log(p.a, p.b); // 1, 42 ``` Ici, l'objet `Proxy` définit une _cible_ (ici c'est un objet vide) et un gestionnaire (_handler_) qui implémente une _trappe_ pour l'opération _get_. Ainsi, l'objet qui est « proxyfié » ne renverra pas `undefined` lorsqu'on tentera d'accéder à une propriété qui n'est pas définie, à la place le nombre 42 sera renvoyé. > **Note :** D'autres exemples sont disponibles sur la page de l'objet {{jsxref("Proxy")}}. ### Terminologie Lorsqu'on utilise les proxies et leurs fonctionnalités, on utilisera les termes suivants : - {{jsxref("Objets_globaux/Proxy/handler","gestionnaire (handler)","","true")}} - : L'objet qui contient les trappes. - trappes - : Les méthodes qui fournissent l'accès aux propriétés. Ce concept est analogue aux trappes utilisées dans les systèmes d'exploitations. - cible - : L'objet que le proxy virtualise. C'est généralement un objet utilisé en arrière-plan pour stocker les informations. Les invariants (c'est-à-dire les éléments sémantiques qui doivent rester inchangés) concernant le caractère non-extensible de l'objet ou l'aspect non-configurable des propriétés sont vérifiés par rapport à cet objet cible. - invariants - : Les éléments sémantiques qui ne doivent pas être modifiés par les opérations définies dans les proxies. Si un invariant n'est pas respecté au sein d'un gestionnaire, cela provoquera une exception {{jsxref("TypeError")}}. ## Les gestionnaires et les trappes Le tableau suivant résume les différentes trappes disponibles pour les objets `Proxy`. Pour plus d'explications et de détails, voir les différents [pages de la référence](/fr/docs/Web/JavaScript/Reference/Objets_globaux/Proxy/handler) sur chacun de ces concepts.
Gestionnaires / Trappes | Opérations interceptées | Invariants |
---|---|---|
{{jsxref("Objets_globaux/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}} |
{{jsxref("Object.getPrototypeOf()")}} {{jsxref("Reflect.getPrototypeOf()")}} {{jsxref("Object/proto", "__proto__")}} {{jsxref("Object.prototype.isPrototypeOf()")}} {{jsxref("Operators/instanceof", "instanceof")}} |
getPrototypeOf doit renvoyer un objet ou
null .Si cible n'est pas
extensible, Object.getPrototypeOf(proxy) doit renvoyer le
même objet que Object.getPrototypeOf(cible) .
|
{{jsxref("Objets_globaux/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}} |
{{jsxref("Object.setPrototypeOf()")}} {{jsxref("Reflect.setPrototypeOf()")}} |
Si |
{{jsxref("Objets_globaux/Proxy/handler/isExtensible", "handler.isExtensible()")}} |
{{jsxref("Object.isExtensible()")}} {{jsxref("Reflect.isExtensible()")}} |
|
{{jsxref("Objets_globaux/Proxy/handler/preventExtensions", "handler.preventExtensions()")}} |
{{jsxref("Object.preventExtensions()")}} {{jsxref("Reflect.preventExtensions()")}} |
|
{{jsxref("Objets_globaux/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}} |
{{jsxref("Object.getOwnPropertyDescriptor()")}} {{jsxref("Reflect.getOwnPropertyDescriptor()")}} |
Une propriété ne peut pas être vue comme non-existante si elle existe comme une propriété propre non-configurable de l'objet cible. Une propriété ne peut pas être vue comme non-existante si elle existe comme une propriété propre de la cible et que l'objet cible n'est pas extensible. Une propriété ne peut pas être vue comme existante si elle n'existe pas comme une propriété propre de l'objet cible et que l'objet cible n'est pas extensible. Une propriété ne peut pas être vue comme non-configurable si elle n'existe pas comme une propriété propre de l'objet cible ou si elle existe comme une propriété configurable propre de l'objet cible.
Le résultat de
|
{{jsxref("Objets_globaux/Proxy/handler/defineProperty", "handler.defineProperty()")}} |
{{jsxref("Object.defineProperty()")}} {{jsxref("Reflect.defineProperty()")}} |
Une propriété ne peut pas être ajoutée si l'objet cible n'est pas extensible. Une propriété ne peut pas être ajoutée ou être modifiée afin d'être non-configurable si elle n'existe pas comme une propriété propre de l'objet cible et qu'elle n'est pas non-configurable. Une propriété peut ne pas être non-configurable si une propriété correspondante configurable existe sur l'objet cible.
Si une propriété possède une propriété correspondante sur l'objet
cible,
En mode strict, si la valeur de retour de
|
{{jsxref("Objets_globaux/Proxy/handler/has", "handler.has()")}} |
Requête d'une propriété :
Requête d'une propriété héritée :
{{jsxref("Reflect.has()")}} |
Une propriété ne peut pas être vue comme non-existante si elle existe comme propriété propre non-configurable de l'objet cible. Une propriété ne peut pas être vue comme non-existante si elle existe comme propriété propre de l'objet cible et que l'objet cible n'est pas extensible. |
{{jsxref("Objets_globaux/Proxy/handler/get", "handler.get()")}} |
Accès à une propriété :
Accès à une propriété héritée :
{{jsxref("Reflect.get()")}} |
La valeur rapportée pour la propriété doit être la même que la valeur de la propriété correspondante sur l'objet cible si celle-ci est une propriété de donnée non accessible en écriture et non-configurable..
La valeur rapportée pour une propriété doit être
|
{{jsxref("Objets_globaux/Proxy/handler/set", "handler.set()")}} |
Affection d'une propriété : |
Il est impossible de modifier la valeur d'une propriété pour que celle-ci soit différente de la valeur de la propriété correspondante de l'objet cible si la propriété de l'objet cible est une propriété de donnée qui n'est pas accessible en écriture et qui n'est pas configurable.
Il est impossible de modifier la valeur d'une propriété si la
propriété correspondante de l'objet cible est une propriété
d'accesseur non-configurable dont l'attribut [[Set]] vaut
En mode strict, si le gestionnaire pour |
{{jsxref("Objets_globaux/Proxy/handler/deleteProperty", "handler.deleteProperty()")}} |
Suppression d'une propriété : |
Une propriété ne peut pas être supprimée si elle existe comme une propriété propre non-configurable de l'objet cible. |
{{jsxref("Objets_globaux/Proxy/handler/enumerate", "handler.enumerate()")}} |
Lister les propriétés avec |
La méthode enumerate doit renvoyer un objet. |
{{jsxref("Objets_globaux/Proxy/handler/ownKeys", "handler.ownKeys()")}} |
{{jsxref("Object.getOwnPropertyNames()")}} |
Le résultat de |
{{jsxref("Objets_globaux/Proxy/handler/apply", "handler.apply()")}} |
|
Il n'y a pas d'invariant pour la méthode handler.apply .
|
{{jsxref("Objets_globaux/Proxy/handler/construct", "handler.construct()")}} |
|
Le résultat doit être un Objet . |