Prefacio
En ES6, el constructor proxy es un objeto global accesible, utilizándolo, puede recopilar varias información sobre las operaciones solicitadas entre el objeto y el comportamiento de varios objetos de operación y devolver lo que desee hacer. Las funciones de flecha, la deconstrucción de la matriz, los parámetros de descanso y otras características en ES6 han circulado ampliamente una vez que se han implementado, pero las características como el proxy rara vez son vistas por los desarrolladores. Por un lado, se debe a la compatibilidad del navegador, y por otro lado, se debe a las ventajas de estas características que los desarrolladores necesitan para comprender profundamente sus escenarios de uso. Personalmente, me gusta mucho el poder de ES6 porque nos permite controlar el acceso externo a los objetos de una manera concisa y fácil de entender. A continuación, primero presentaré cómo se usa el proxy y luego enumere ejemplos específicos para explicar los escenarios de uso del proxy.
El proxy , ver el nombre y el significado, tiene una función muy similar al modo proxy en el modo de diseño, que a menudo se usa en tres aspectos:
1. Monitorear el acceso externo a los objetos
2. Función o complejidad de clase
3. Verifique la operación o administre los recursos requeridos antes de la operación
En un entorno de navegador que admite proxy, el proxy es un objeto global que puede usarse directamente. Proxy(target, handler) es un constructor, target es el objeto que se está procesando, y handlder es un objeto que declara varias operaciones proxy y finalmente devuelve un objeto proxy. Cada vez que el mundo exterior accede a las propiedades del objeto target a través del objeto proxy, pasa a través del objeto handler . A partir de este proceso, el objeto proxy es muy similar al middleware (middleware). Entonces, ¿qué operaciones pueden interceptar proxy? Las operaciones más comunes son (leer), establecer (modificar) las propiedades del objeto, etc. Haga clic aquí para obtener una lista completa de operaciones interceptables. Además, el objeto proxy también proporciona un método revoke que puede iniciar sesión todas las operaciones proxy en cualquier momento. Antes de introducir formalmente proxy, le recomendamos que tenga una cierta comprensión de Reflect, que también es un nuevo objeto global agregado a ES6.
Básico
const target = {name: 'billy bob', edad: 15}; const handler = {get (target, key, proxy) {const hoy = new Date (); console.log (`obtener solicitud realizada por $ {key} a $ {hoy}`); return reflej.get (objetivo, clave, proxy); }}; const proxy = new Proxy (Target, Handler); proxy.name; // => "Obtenga solicitud de nombre en el julio del 21 de julio de 2016 15:26:20 GMT+0800 (CST)" // => "Billy Bob" En el código anterior, primero definimos que un objeto target sea proxyed y luego declaramos un objeto handler que contiene todas las operaciones de proxy. A continuación, usamos Proxy(target, handler) para crear el proxy del objeto Proxy. Después de eso, todos los accesos al atributo target utilizando proxy serán procesados por handler .
1. Salga del módulo de verificación
Comencemos con una verificación de tipo simple, que demuestra cómo usar proxy para garantizar la precisión de los tipos de datos:
Sea numericDatastore = {Count: 0, cantidad: 1234, total: 14}; numericDatastore = new Proxy (numericDatastore, {set (target, key, value, proxy) {if (typeOf value! == '' number ') {throwing ("Las propiedades en numericDatastore solo pueden ser números"); }}); // Se lanzó un error porque "foo" no es un numericdatastore.count = "foo"; // asignado con éxito numericDatastore.count = 333;Si desea desarrollar un verificador directamente para todas las propiedades de un objeto, puede hacer que la estructura del código sean hinchadas, utilizando Proxy, puede separar el verificador de la lógica del núcleo y entrar en uno:
function createValidator (target, validator) {return new proxy (target, {_validator: validator, set (target, key, valor, proxy) {if (target.hasownproperty (key)) {let validator = this._validator [key]; if (validator (valor)) {return reflej.set (target, key, value, value, proxy);} establecer $ {Key} a $ {valor}. }, edad (val) {return typeOf Age === 'Number' && Age> 18; }} Persona de clase {Constructor (nombre, edad) {this.name = name; this.age = edad; devolver createValidator (this, persona Validators); }} const bill = nueva persona ('bill', 25); // Las siguientes operaciones informarán un error bill.name = 0; bill.age = 'bill'; bill.age = 15; A través de la separación del verificador y la lógica principal, puede extender infinitamente el contenido del verificador personValidators sin causar daño directo a las clases o funciones relevantes. Para ser más complicados, también podemos usar proxy para simular el tipo de verificación para verificar si la función recibe parámetros con el tipo y la cantidad correctos:
let obj = { pickyMethodOne: function(obj, str, num) { /* ... */ }, pickyMethodTwo: function(num, obj) { /*... */ }};const argTypes = { pickyMethodOne: ["object", "string", "number"], pickyMethodTwo: ["number", "object"]};obj = new Proxy(obj, {get: function (target, key, proxy) {val vals = target [key]; function argChecker (nombre, args, verificadores) {for (var idx = 0; idx <args.length; idx ++) {var arg = args [idx]; var type = checkers [IDX]; if (! arg || typeof arg! == type) {console.warn (`está implementando incorrectamente la firma de $ {name}. Verifique param $ {idx + 1}`); }}} obj.pickymethodone (); //> está implementando incorrectamente la firma de techodono. Compruebe Param 1 //> está implementando incorrectamente la firma de PickyMetodona. Compruebe Param 2 //> Está implementando incorrectamente la firma de PickyMetodona. Verifique param 3obj.pickymethodtwo ("wopdapodoo", {}); //> está implementando incorrectamente la firma de techodono. Verifique param 3obj.pickymethodtwo ("wopdapodoo", {}); //> está implementando incorrectamente la firma de techodono. Verifique param 3obj.pickymethodtwo ("wopdapodoo", {}); //> está implementando incorrectamente la firma de PickyMethodwo. Verifique el parámetro 1 // sin advertencias loggedobj.pickymethodone ({}, "una pequeña cadena", 123); obj.pickymethodone (123, {});2. Atributos privados
En JavaScript u otros idiomas, es habitual agregar un _ antes del nombre de la variable para indicar que esta es una propiedad privada (no realmente privada), pero no podemos garantizar que nadie acceda o modifique. En el siguiente código, declaramos un apiKey privado para facilitar las llamadas de método dentro del objeto api , pero no queremos poder acceder api._apiKey desde el exterior:
var api = { _apiKey: '123abc456def', /* mock methods that use this._apiKey */ getUsers: function(){}, getUser: function(userId){}, setUser: function(userId, config){}};// logs '123abc456def';console.log("An apiKey we want to keep private", api._apikey); // get y mutate _apikeys como se desee apikey = api._apikey; api._apikey = '987654321';Obviamente, la convención no tiene restricciones. Usando el proxy ES6, podemos implementar variables privadas reales. A continuación se demuestra dos métodos privados diferentes para diferentes métodos de lectura.
El primer método es usar SET/GOLE para interceptar solicitudes de lectura y escritura y devolver undefined:
Let api = {_apikeY: '123ABC456DEF', getUsers: function () {}, getUser: function (userId) {}, setUser: function (userId, config) {}}; const restringidos = ['_apikey']; api = new proxy (api, {get (target, key, proxy) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if) {if). > -1) {Error de lanzamiento (`$ {Key} está restringido. Consulte la documentación de API para obtener más información. Reflejar.get (Target, Key, Value, Proxy);El segundo método es usar tiene intercepción en operación:
var api = {_apikeY: '123ABC456DEF', getUsers: function () {}, getUser: function (userId) {}, setUser: function (userId, config) {}}; const restricted = ['_apikey']; api = new proxy (api, {ha (target, key) {retorno de retorno (restringido) ? Proxy oscurece _apikey ... ")}}3. Registro de acceso
Para atributos o interfaces que con frecuencia llaman, ejecutan lentamente o toman más recursos en el entorno de ejecución, los desarrolladores querrán registrar su uso o rendimiento. En este momento, pueden usar proxy para actuar como el middleware e implementar fácilmente la función de registro:
Let api = {_apikeY: '123ABC456Def', getUsers: function () { / * ... * /}, getUser: function (userId) { / * ... * /}, setUser: function (userId, config) { / * /}}; function logmethodasync (timestamp, método) {settimeout (function () {) {) console.log (`$ {timestamp} - loging $ {método} solicitud asynchrony.`); };}}); api.getusers ();4. Advertencia e intercepción temprana
Supongamos que no desea que otros desarrolladores eliminen el atributo noDelete , y quieran que los desarrolladores que llaman a oldMethod comprendan que este método ha sido abandonado, o les dan a los desarrolladores que no modifiquen doNotChange , entonces puede usar proxy para implementarlo:
Let dataStore = {nodelete: 1235, Oldmethod: function () {/*...*/}, Donotchange: "probado y verdadero"}; const nodelete = ['nodelete']; const nochange = ['Donotchange']; const Depreced = ['Oldmethod']; dataStore = new Proxy (DataStore, {set (Target, Key, Value, Proxy) {if (noChange.includes (Key)) {Error de lanzamiento (`Error! $ {Key} es inmutable.`);} return reflej.set (target, key, value, proxy);}, deletear (target) Error (`Error! $ {Key} no se puede eliminar. function (... args) {refleat.apply (Target [Key], Target, Args); Eliminar DataStore.nodelete; datastore.oldmethod ();5. Operación de filtro
Algunas operaciones tomarán recursos, como transferir archivos grandes. En este momento, si el archivo ya se envía en fragmentos, no hay necesidad de hacer que la nueva solicitud correspondiente (no absolte) sea correspondiente. En este momento, puede usar proxy para detectar la característica de la solicitud y filtrar cuáles no necesitan responder y cuáles deben responder de acuerdo con las características. El siguiente código demuestra brevemente cómo filtrar las funciones, no el código completo. Creo que todos entenderán las cosas maravillosas:
Sea obj = {getGiantFile: function (fileId) {/*...*/}}; obj = new proxy (obj, {get (target, key, proxy) {return function (... args) {const id = args [0]; dejar isenRoute = checkenRoute (id); let downlowing = checkStatus (id); stamps; stamps; (isenRoute || iSdownloading) {return false;6. Agente de interrupción
Proxy admite la no exhibición a target en cualquier momento, que a menudo se usa para encerrar completamente el acceso a datos o interfaces. En el siguiente ejemplo, utilizamos el método Proxy.revocable para crear un objeto proxy que revocablemente proxies:
LET SENSITIVETATA = {UserName: 'DevBryce'}; const {SensIdiveData, revokeAcCess} = proxy.Revocable (sensitiveData, handler); function handleSuspectedHack () {revokeAccess ();} // logbryce'console.log (sensitivedata.usame); HandlesUspectedHack (); // typeError: RevokedConsole.log (SensIdiveData.Username);Decorador
El decorador implementado en ES7 es equivalente al modo decorador en el modo de diseño. Si simplemente distingue los escenarios de uso de proxy y decorador , se puede resumir como: la función central del proxy es controlar el acceso del mundo exterior al agente, y la función central del decorador es mejorar las funciones del decorador. Siempre que hagan una buena diferencia en sus escenarios de uso central, funciones como registros de acceso, aunque este artículo utiliza la implementación proxy, también se pueden implementar usando decorador. Los desarrolladores pueden elegir libremente según las necesidades del proyecto, las especificaciones del equipo y sus propias preferencias.
Resumir
El poder de ES6 sigue siendo muy práctico. Sus características aparentemente simples son de gran utilidad. Espero que sea útil para todos aprender ES6.