JavaScript Proxy et Reflect
Apprenez comment fonctionnent JavaScript Proxy et Reflect : interceptez get, set, apply, has et delete avec des traps, et appliquez des proxies pour la validation, le contrôle d'accès et la journalisation.
Les proxies JavaScript vous permettent d'intercepter et de redéfinir les opérations fondamentales sur les objets — lire une propriété, l'écrire, vérifier si une clé existe, appeler une fonction, et bien plus. Associés à l'API Reflect, qui effectue ces mêmes opérations de manière « par défaut », les proxies offrent un mécanisme propre et officiel pour ajouter des comportements aux objets sans les modifier directement.
Ce chapitre couvre ce qu'est un proxy, les traps les plus courants (get, set, apply, has, deleteProperty), comment Reflect complète les proxies, ainsi que plusieurs patterns concrets tels que la validation, le contrôle d'accès et la journalisation.
Qu'est-ce qu'un Proxy
Un Proxy enveloppe un objet cible et un handler. Le handler est un ensemble de fonctions appelées traps, chacune interceptant une opération spécifique. Lorsque vous interagissez avec le proxy, le trap correspondant s'exécute à la place du comportement par défaut ; si aucun trap n'est défini pour une opération, le proxy la transmet à la cible sans modification.
Cela s'avère utile chaque fois que vous souhaitez superposer des comportements transversaux — journalisation, validation, valeurs par défaut, règles d'accès — sur un object sans toucher à son propre code.
Syntaxe de Proxy
const proxy = new Proxy(target, handler);target: L'object original dont vous souhaitez intercepter les opérations.handler: Un object dont les méthodes (traps) définissent le comportement des opérations.
Vous utilisez ensuite proxy exactement comme vous utiliseriez l'object original ; la différence est que vos traps s'exécutent entre les deux.
Comprendre le trap get
Le trap get intercepte les lectures de propriétés sur l'object cible. Il reçoit la target, la clé property et le receiver (le proxy lui-même). Il est souvent utilisé pour journaliser les accès, calculer des propriétés à la volée, ou retourner des valeurs par défaut pour les clés manquantes.
Exemple :
Ce code configure un proxy pour journaliser les accès aux propriétés d'un object.
- Handler : Définit un trap
getpour journaliser la propriété accédée. - Object cible : Contient les propriétés
nameetage. - Proxy : Enveloppe l'object
targetavec lehandler.
Lorsque proxy.name est accédé, il journalise "Getting name" et retourne "John". Cela est utile pour surveiller ou déboguer les accès aux propriétés.
Manipulation des opérations sur les objets avec les traps set et apply
Le trap set
Le trap set peut imposer des règles pour les affectations de propriétés, garantissant que les propriétés contiennent des types spécifiques ou satisfont certaines conditions.
Exemple :
Ce code configure un proxy pour valider et journaliser les affectations de propriétés sur un object.
- Handler : Définit un trap
setpour vérifier la propriétéageavec des valeurs valides et journaliser les tentatives de modification. - Proxy : Enveloppe l'object
targetavec lehandler.
Lorsque proxy.age est défini, il vérifie s'il s'agit d'un âge valide (0-150). Si invalide, il journalise une erreur et lève une exception.
Le trap apply
La méthode apply dans un JavaScript Proxy intercepte les appels de fonctions. Elle prend trois arguments :
- target : La fonction originale appelée.
- thisArg : La valeur de
thisà l'intérieur de la fonction. - argumentsList : Un array d'arguments passés à la fonction.
Exemple :
Ce code configure un proxy pour journaliser les appels de fonctions et leurs arguments.
- Handler : Définit un trap
applypour journaliser les arguments lorsque la fonction est appelée. - Fonction :
sumadditionne deux nombres. - Proxy : Enveloppe la fonction
sumavec lehandler.
Dans le code fourni, le trap apply journalise les arguments puis appelle la fonction originale via target.apply(thisArg, argumentsList). Cela est utile pour la journalisation, le débogage, ou la modification dynamique du comportement des fonctions.
Le trap has
Le trap has intercepte l'opérateur in. Une utilisation courante consiste à masquer les clés « privées » (par convention, les noms commençant par _) afin qu'elles ne semblent pas exister de l'extérieur.
Exemple :
Même si _secret existe toujours sur la cible, l'opérateur in retourne false, de sorte que la clé est effectivement masquée du code qui sonde l'object.
Le trap deleteProperty
Le trap deleteProperty intercepte l'opérateur delete, vous permettant de protéger certaines clés contre la suppression. Il doit retourner true lorsque la suppression est autorisée, ou lever une exception pour la bloquer en mode strict.
Exemple :
Les proxies JavaScript sont puissants, mais utilisez-les avec discernement. Un usage excessif des proxies peut rendre votre code plus difficile à comprendre et à maintenir. Notez que les proxies introduisent une légère surcharge de performance par rapport aux objets natifs.
L'API Reflect
Reflect est un objet intégré qui fournit une méthode pour chaque opération interceptable — exactement le même ensemble que celui couvert par les traps de proxy (Reflect.get, Reflect.set, Reflect.has, Reflect.deleteProperty, Reflect.apply, etc.). Chaque méthode exécute la version par défaut de cette opération.
Cela fait de Reflect le compagnon naturel de Proxy : à l'intérieur d'un trap, vous souhaitez généralement ajouter un comportement puis laisser l'opération se dérouler normalement. Appeler la méthode Reflect correspondante fait exactement cela, et elle transmet correctement le receiver (important pour les getters/setters), ce qu'un simple target[property] ne fait pas. Vous verrez ce pattern utilisé dans les exemples pratiques ci-dessous.
Les méthodes Reflect retournent également des valeurs au lieu de lever des exceptions — par exemple Reflect.set retourne un boolean indiquant le succès — ce qui rend les opérations plus prévisibles que leurs équivalents opérateurs ou Object.*.
Voici un aperçu rapide des principales méthodes Reflect :
1. Reflect.get()
Cette méthode est utilisée pour obtenir la valeur d'une propriété d'un object.
Exemple :
2. Reflect.set()
Cette méthode est utilisée pour définir la valeur d'une propriété sur un object.
Exemple :
3. Reflect.has()
Cette méthode vérifie si une propriété existe dans un object.
Exemple :
4. Reflect.deleteProperty()
Cette méthode supprime une propriété d'un object.
Exemple :
5. Reflect.ownKeys()
Cette méthode retourne toutes les clés de propriétés propres d'un object.
Exemple :
6. Reflect.apply()
Cette méthode appelle une fonction cible avec les arguments donnés.
Exemple :
7. Reflect.construct()
Cette méthode est utilisée pour créer une nouvelle instance d'un object.
Exemple :
Ces exemples montrent comment vous pouvez utiliser les méthodes Reflect pour effectuer des opérations courantes sur les objets de manière plus propre et plus cohérente.
Cas d'utilisation pratiques des proxies JavaScript
Exemple 1 : Initialisation automatique des propriétés
Description : Utilisez les proxies JavaScript pour initialiser automatiquement les propriétés undefined dans un object. Cela peut être utile dans des situations où les objets sont remplis dynamiquement avec des données au fil du temps, comme les paramètres utilisateur ou les configurations qui peuvent ne pas être définis initialement.
Ce code crée un proxy qui vérifie si une propriété existe sur un object. Si ce n'est pas le cas, le proxy définit automatiquement une valeur par défaut. Cela aide à prévenir les erreurs liées aux propriétés manquantes.
Exemple 2 : Contrôle d'accès
Description : Les proxies peuvent imposer des permissions de lecture ou d'écriture sur les propriétés d'un object. Cet exemple démontre un proxy qui empêche la lecture ou l'écriture de certaines propriétés en fonction de règles prédéfinies, ce qui est particulièrement utile pour gérer l'accès aux données sensibles.
Ce code sécurise un object en contrôlant l'accès à ses propriétés. Il bloque la lecture de 'sensitiveData' et empêche la modification des propriétés 'readOnly', contribuant à protéger les données.
Exemple 3 : Journalisation et débogage
Description : Les proxies peuvent être utilisés pour journaliser les interactions avec un object, ce qui aide au débogage et à la surveillance des opérations. Cet exemple crée un proxy qui journalise toutes les opérations get, set et les appels de méthodes effectués sur un object.
Ce code suit chaque fois que quelqu'un accède à une propriété de l'object ou la modifie, ce qui est idéal pour comprendre ce que fait votre code et quand.
Exemple 4 : Validation des données
Description : Utilisez les proxies pour la validation à la volée des propriétés d'un object. Cela est particulièrement utile pour garantir l'intégrité des données lorsque les objets sont mis à jour dynamiquement dans une application.
Cet exemple démontre comment utiliser le Proxy de JavaScript pour valider et journaliser les changements de propriétés. L'object validator vérifie si la propriété age est un nombre valide compris entre 0 et 150. Si ce n'est pas le cas, il journalise une erreur et lève une exception. Sinon, il journalise la nouvelle valeur et met à jour la propriété. L'object person utilise ce validateur pour gérer sa propriété age, garantissant que les âges invalides sont détectés et journalisés.
Conclusion
Maîtriser les proxies JavaScript vous permet de contrôler et d'étendre le comportement des objets sans les modifier directement. Les proxies peuvent imposer des règles de validation et d'accès, fournir des valeurs par défaut, et alimenter des outils de journalisation ou de débogage, tandis que Reflect maintient les opérations sous-jacentes propres et prévisibles. Utilisés avec parcimonie, ils vous aident à créer des applications plus dynamiques et sécurisées.
Pour approfondir les opérations que les proxies interceptent, consultez les getters et setters de propriétés et les indicateurs et descripteurs de propriétés. Pour le pattern de validation présenté ci-dessus, la gestion des erreurs avec try...catch et les classes sont des compagnons utiles.