Préface
Dans ES6, le constructeur proxy est un objet global accessible, en l'utilisant, vous pouvez collecter diverses informations sur les opérations demandées entre l'objet et le comportement de divers objets d'opération et renvoyer ce que vous voulez faire. Les fonctions de flèche, la déconstruction du tableau, les paramètres de repos et d'autres fonctionnalités dans ES6 ont été largement diffusées une fois qu'ils ont été mis en œuvre, mais des fonctionnalités comme le proxy sont rarement vues par les développeurs. D'une part, c'est à cause de la compatibilité du navigateur, et d'autre part, c'est à cause des avantages de ces fonctionnalités dont les développeurs ont besoin pour comprendre profondément leurs scénarios d'utilisation. Personnellement, j'aime vraiment le proxy d'ES6 car cela nous permet de contrôler l'accès externe aux objets d'une manière concise et facile à comprendre. Dans ce qui suit, je vais d'abord présenter comment le proxy est utilisé, puis énumérer des exemples spécifiques pour expliquer les scénarios d'utilisation de proxy.
Proxy , voir le nom et le sens, a une fonction très similaire au mode proxy en mode conception, qui est souvent utilisé en trois aspects:
1. Surveiller l'accès externe aux objets
2. Fonction ou complexité de classe
3. Vérifiez l'opération ou gérez les ressources requises avant l'opération
Dans un environnement de navigateur qui prend en charge le proxy, le proxy est un objet global qui peut être utilisé directement. Proxy(target, handler) est un constructeur, target est l'objet poursuivi et handlder est un objet qui déclare diverses opérations de proxy et renvoie enfin un objet proxy. Chaque fois que le monde extérieur accède aux propriétés de target via l'objet proxy, il passe par l'objet handler . À partir de ce processus, l'objet proxy est très similaire au middleware (middleware). Alors, quelles opérations peuvent procurer l'interception? Les opérations les plus courantes sont les propriétés d'objet GET (lire), définir (modifier), etc. Veuillez cliquer ici pour une liste complète des opérations interceptables. De plus, l'objet proxy fournit également une méthode revoke qui peut déconnecter toutes les opérations proxy à tout moment. Avant d'introduire officiellement un proxy, nous vous recommandons d'avoir une certaine compréhension de Reflect, qui est également un nouvel objet global ajouté à ES6.
Basique
const cible = {name: 'billy bob', Âge: 15}; const handler = {get (cible, key, proxy) {const aujourd'hui = new Date (); Console.log (`Getez la demande fait pour $ {key} à $ {aujourd'hui}`); return Reflect.get (cible, clé, proxy); }}; const proxy = new proxy (cible, handler); proxy.name; // => "remettre une demande pour le nom à jeu 21 juil 2016 15:26:20 GMT + 0800 (CST)" // => "Billy Bob" Dans le code ci-dessus, nous définissons d'abord un objet target à proxy, puis déclarons un objet handler contenant toutes les opérations de proxy. Ensuite, nous utilisons Proxy(target, handler) pour créer le proxy d'objet proxy. Après cela, tous les accès à target à l'aide proxy seront traités par handler .
1. Quittez le module de vérification
Commençons par une vérification de type simple, qui montre comment utiliser le proxy pour assurer la précision des types de données:
Laissez NumericDatastore = {Count: 0, Montant: 1234, Total: 14}; NumericDatastore = Nouveau proxy (Numericdatastore, {set (cible, Key, Value, Proxy) {if (typeof Value! }}); // Une erreur a été lancée parce que "foo" n'est pas un Numericdatastore.count = "foo"; // attribué avec succès Numericdatastore.count = 333;Si vous souhaitez développer un vérificateur directement pour toutes les propriétés d'un objet, il peut rapidement rendre la structure de code gonflée, en utilisant le proxy, vous pouvez séparer le vérificateur de la logique centrale et entrer en un:
fonction créévalidator (cible, validateur) {return new proxy (cible, {_validator: validator, set (target, key, valeur, proxy) {if (target.hasownproperty (key)) {let validator = this._validator [key]; if (!! validator (value) {return réfléchir. Error (`ne peut pas définir $ {key} sur $ {valeur}. Invalid.`);}} else {throw error (` $ {key} n'est pas une propriété valide`)}}}});} const PersonValidator = {name (val) {return typeof Val == 'String'; }, Âge (val) {return typeof Âge === 'Number' && âge> 18; }} classe de classe {constructeur (nom, âge) {this.name = name; this.age = âge; Retour CreateValidator (ceci, PersonValidators); }} const Bill = new Person ('Bill', 25); // Les opérations suivantes rapporteront une erreur Bill.Name = 0; Bill.age = 'Bill'; bill.age = 15; Grâce à la séparation du vérificateur et de la logique principale, vous pouvez étendre infiniment le contenu du vérificateur personValidators sans causer des dommages directs aux classes ou fonctions pertinentes. Pour être plus compliqué, nous pouvons également utiliser le proxy pour simuler la vérification du type pour vérifier si la fonction reçoit des paramètres avec un type et une quantité correct:
Soit obj = {pickymethodone: fonction (obj, str, num) {/ * ... * /}, pickymethodtwo: function (num, obj) {/ * ... * /}}; const argtypes = {pickymethodone: ["objet", "string", "nombre"], pickythodtwo: ["nombre", "objet"]} {get: function (Target, key, proxy) {var valeur = cible [key]; fonction argChecker (name, args, checkers) {for (var idx = 0; idx <args.length; idx ++) {var arg = args [idx]; var type = checkers [idx]; if (! arg || typeof arg! == type) {console.warn (`vous implémentez mal la signature de $ {nom}. Vérifiez param $ {idx + 1}`); }}} obj.PickyMethodone (); //> Vous implémentez mal la signature de la pickyméthodone. Vérifiez Param 1 //> Vous implémentez mal la signature de la pickyméthodone. Vérifiez Param 2 //> Vous implémentez mal la signature de la pickyméthodone. Vérifier param 3oBj.PickyMethodTwo ("wopdapodoo", {}); //> Vous implémentez mal la signature de la pickyméthodone. Vérifier param 3oBj.PickyMethodTwo ("wopdapodoo", {}); //> Vous implémentez mal la signature de la pickyméthodone. Vérifier param 3oBj.PickyMethodTwo ("wopdapodoo", {}); //> Vous implémentez mal la signature de pickymethodtwo. Vérifiez param 1 // aucun avertissement loggedobj.PickyMethodone ({}, "une petite chaîne", 123); obj.PickyMethodone (123, {});2. Attributs privés
Dans JavaScript ou d'autres langues, il est habituel d'ajouter un _ avant le nom de la variable pour indiquer qu'il s'agit d'une propriété privée (pas vraiment privée), mais nous ne pouvons garantir que personne ne l'accèdera ou ne le modifiera. Dans le code suivant, nous déclarons un apiKey privé pour faciliter les appels de méthode à l'intérieur de l'objet api , mais nous ne voulons pas pouvoir accéder api._apiKey de l'extérieur:
var api = {_apikey: '123abc456def', / * MOCK Méthodes qui utilisent this._apikey * / getUSERS: function () {}, getuser: function (userid) {}, setter: function (userId, config) {}}; // logs '123abc456def'; api._apikey); // obtenir et muter _apikeys comme souhaité apikey = api._apikey; api._apikey = '987654321';De toute évidence, la convention n'est pas retenue. En utilisant le proxy ES6, nous pouvons implémenter de véritables variables privées. Ce qui suit démontre deux méthodes privées différentes pour différentes méthodes de lecture.
La première méthode consiste à utiliser SET / GET pour intercepter les demandes de lecture et d'écriture et de retourner undefined:
LET api = {_apikey: '123abc456def', getUsers: function () {}, getuser: function (userid) {}, setter: function (userid, config) {}}; construt = ['_apikey']; api = new proxy (api, {get (cible, key, proxy) {if (reposof, {get (Target, key, proxy) {if (reposof, {get (cible, key, proxy) {if (reposof > -1) {lancer une erreur ($ {key} est restreint. Veuillez voir la documentation API pour plus d'informations. Reflect.get (Target, Key, Value, Proxy);}}); // Les opérations suivantes lanceront une console d'erreur.log (api._apikey); api._apikey = '987654321';La deuxième méthode consiste à utiliser une interception en fonctionnement:
var api = {_apikey: '123abc456def', getUsers: function () {}, getuser: function (userId) {}, setter: function (userId, config) {}}; const restrect = ['_apikey']; api = new proxy (api) ? proxy obscurci _apikey ... ")}}3. Journal d'accès
Pour les attributs ou les interfaces qui appellent fréquemment, s'exécutent lentement ou prennent plus de ressources dans l'environnement d'exécution, les développeurs voudront enregistrer leur utilisation ou leurs performances. À l'heure actuelle, ils peuvent utiliser le proxy pour agir comme middleware et implémenter facilement la fonction de journalisation:
Let api = {_apikey: '123abc456def', getUsers: function () {/ * ... * /}, getuser: function (userId) {/ * ... * /}, seduser: function (userid, config) {/ * ... * /}}; function logmethodasy Console.log (`$ {horodatage} - Logging $ {méthode} demande de manière asynchrone.`);}, 0)} api = new proxy (api, {get: function (cible, key, proxy) {var value = cible [key]; return function. };}}); api.getUser ();4. Avertissement précoce et interception
Supposons que vous ne vouliez pas que d'autres développeurs suppriment l'attribut noDelete et que les développeurs qui appellent oldMethod comprennent que cette méthode a été abandonnée, ou dire aux développeurs de ne pas modifier doNotChange , alors vous pouvez utiliser la proxy pour l'implémenter:
Laissez DataStore = {nodelete: 1235, oldMethod: function () {/*...*/}, donotchange: "Trip and True"}; const nodelete = ['nodelete']; const Nochange = ['donotchange']; const déprécés = ['oldmethod']; DataStore = new proxy (DataStore, {set (cible, clé, valeur, proxy) {if (nochange.includes (key)) {throw error (`error! $ {key} est immuable. Error (Erreur! Fonction (... args) {reflev. supprimer datastore.nodelete; DataStore.oldMethod ();5. Fonctionnement du filtre
Certaines opérations prendront beaucoup de ressources, comme le transfert de fichiers volumineux. À l'heure actuelle, si le fichier est déjà envoyé en morceaux, il n'est pas nécessaire de faire correspondant (non absolute) à la nouvelle demande. Pour le moment, vous pouvez utiliser le proxy pour détecter la fonctionnalité de la demande et filtrer lesquelles n'ont pas besoin de répondre et lesquelles doivent répondre en fonction des fonctionnalités. Le code suivant montre brièvement comment filtrer les fonctionnalités, pas le code complet. Je crois que tout le monde comprendra les choses merveilleuses:
LET OBJ = {GetgiantFile: fonction (fileId) {/*...*/}}; obj = new proxy (obj, {get (cible, key, proxy) {return function (... args) {const id = args [0]; let itenRoute = checkenRoute (id); let isownloading = checkstatus (id); LETCACKED = GetCached); if); if) (id); id); Let Cached = GetCached); if) (iSenRoute || Isdownloading) {return false;} if (cached) {return cached;} return Reflect.6. Agent d'interruption
Le proxy prend en charge le perfodité aux target à tout moment, qui est souvent utilisée pour enfermer complètement l'accès aux données ou aux interfaces. Dans l'exemple suivant, nous avons utilisé la méthode Proxy.revocable .
LET SENSITIVEDATA = {Username: 'DevBryce'}; const {Sensivevedata, RevokeAccess} = proxy.Revocable (Sensivevedata, Handler); Function HandleSpecyHack () {RevokeAccess ();} // Logs 'DevBryce'Console.log (Sensivedata.username); handleSespectedHack (); // typeError: RevokedConsole.log (Sensivevedata.Username);Décorateur
Le décorateur implémenté dans ES7 est équivalent au mode décorateur en mode conception. Si vous distinguez simplement les scénarios d'utilisation de proxy et de décorateur , il peut être résumé comme: La fonction centrale du proxy est de contrôler l'accès du monde extérieur à l'agent, et la fonction centrale du décorateur est d'améliorer les fonctions du décorateur. Tant qu'ils font une bonne différence dans leurs scénarios d'utilisation de base, des fonctions telles que les journaux d'accès, bien que cet article utilise l'implémentation de proxy, ils peuvent également être implémentés à l'aide du décorateur. Les développeurs peuvent choisir librement en fonction des besoins du projet, des spécifications de l'équipe et de leurs propres préférences.
Résumer
Le proxy d'ES6 est toujours très pratique. Ses fonctionnalités apparemment simples sont très utiles. J'espère qu'il sera utile à tout le monde d'apprendre ES6.