A lo largo de los años, JavaScript se ha convertido en un lenguaje de programación poderoso y adaptable, en constante evolución para satisfacer las necesidades cambiantes de los desarrolladores.
Uno de sus avances relativamente recientes es el objeto Proxy, que permite a los programadores crear objetos potentes y flexibles capaces de interceptar y modificar operaciones clave en otros objetos.
Este artículo profundiza en las capacidades de Proxy en JavaScript , cubriendo su sintaxis, atributos, aplicaciones típicas, fortalezas, limitaciones, instancias ilustrativas y enfoques recomendados.
Un Proxy es un objeto que envuelve a otro objeto e intercepta operaciones básicas en él, como acceder, asignar y eliminar propiedades. El proxy es un aspecto crucial de JavaScript que permite a los desarrolladores escribir código más versátil y robusto.
El objetivo de este artículo es brindar una comprensión integral de Proxy en JavaScript, que abarque su sintaxis, características, beneficios, inconvenientes, ilustraciones y técnicas recomendadas.
Proxy de JavaScript es una capacidad que permite la creación de objetos capaces de modificar y personalizar las operaciones básicas realizadas en otros objetos.
Para establecer un objeto Proxy, se necesitan dos componentes: un objeto de destino y un objeto controlador. El objeto de destino es aquel en el que se van a interceptar las operaciones, mientras que el objeto controlador es responsable de contener las trampas, o métodos, utilizados para capturar estas operaciones.
Aquí hay un ejemplo que demuestra cómo crear un objeto Proxy básico:
const target = { name: 'John', age: 25, }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); return target[prop]; }, }; const proxy = new Proxy(target, handler); console.log(proxy.name); // Getting property name // John
En este ejemplo, generamos un objeto de destino que tiene dos características: nombre y edad. También generamos un objeto controlador que tiene una captura de captura para capturar cualquier intento de leer una propiedad en el objeto de destino. Después de eso, producimos un objeto Proxy al proporcionar los objetos de destino y controlador al constructor Proxy. Por último, recuperamos la propiedad de nombre del objeto Proxy, que invoca la trampa de obtención y envía un mensaje a la consola.
Las trampas son métodos que interceptan operaciones en el objeto de destino. Hay varias trampas que puede usar con un objeto Proxy, incluidas get, set, has, deleteProperty y más.
Aquí hay una breve descripción de algunas de las trampas más utilizadas:
get : esta trampa intercepta los intentos de leer una propiedad en el objeto de destino. Toma dos argumentos: el objeto de destino y la propiedad a la que se accede. La trampa devuelve el valor de la propiedad.
set : esta trampa captura cualquier esfuerzo por establecer una propiedad en el objeto de destino. Requiere tres parámetros: el propio objeto de destino, la propiedad que se está estableciendo y el valor actualizado de esa propiedad. El mecanismo tiene la capacidad de alterar el valor que se está estableciendo, o puede generar un error para prohibir que se establezca el valor.
has : esta trampa intercepta los intentos de comprobar si existe una propiedad en el objeto de destino. Toma dos argumentos: el objeto de destino y la propiedad que se está comprobando. La trampa devuelve un valor booleano que indica si la propiedad existe o no.
deleteProperty : esta trampa intercepta los intentos de eliminar una propiedad del objeto de destino. Toma dos argumentos: el objeto de destino y la propiedad que se está eliminando. La trampa puede eliminar la propiedad o generar un error para evitar que se elimine la propiedad.
Los objetos proxy poseen una característica fascinante que permite invalidarlos, lo que hace que sus trampas ya no intercepten operaciones en el objeto de destino. Para construir un objeto Proxy que pueda invalidarse, utilice la función Proxy.revocable()
.
Aquí hay un ejemplo:
const target = { name: 'John', age: 25, }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); return target[prop]; }, }; const {proxy, revoke} = Proxy.revocable(target, handler); console.log(proxy.name); // Getting property name // John revoke(); console.log(proxy.name); // Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked
En este ejemplo, creamos un objeto Proxy revocable utilizando el método Proxy.revocable()
. Luego accedemos a la propiedad de nombre del objeto Proxy, que activa la trampa de obtención y registra un mensaje en la consola. Luego revocamos el objeto Proxy usando el método revoke()
, lo que significa que cualquier otro intento de acceder a las propiedades del objeto Proxy fallará.
Otra característica interesante de los objetos Proxy es que pueden usarse para implementar patrones de herencia en JavaScript. Al utilizar un objeto Proxy como prototipo de otro objeto, puede interceptar búsquedas de propiedades y personalizar el comportamiento de la cadena de prototipos.
Aquí hay un ejemplo:
const parent = { name: 'John', }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); if (!(prop in target)) { return Reflect.get(parent, prop); } return target[prop]; }, }; const child = new Proxy({}, handler); console.log(child.name); // Getting property name // John child.name = 'Bob'; console.log(child.name); // Getting property name // Bob console.log(parent.name); // John
En este ejemplo, se define un objeto principal y tiene un atributo de nombre. Luego, creamos un objeto controlador con una trampa de obtención que evita cualquier solicitud de lectura para las propiedades del objeto secundario. La trampa usa el método Reflect.get() para recurrir al objeto principal si la propiedad está ausente en el objeto secundario.
Luego, usando un objeto Proxy como prototipo y el objeto controlador como controlador, construimos un objeto secundario. Finalmente, obtenemos acceso y modificamos la propiedad del nombre del objeto secundario, lo que activa las trampas de obtención y configuración y registra los mensajes en la consola.
Un caso de uso para Proxy es almacenar en caché costosas llamadas a funciones. En este ejemplo, creamos un objeto Proxy que almacena en caché el resultado de una llamada de función en función de sus argumentos.
function calculateCost(price, taxRate) { console.log('Calculating cost...'); return price * (1 + taxRate); } const cache = new Map(); const proxy = new Proxy(calculateCost, { apply(target, thisArg, args) { const key = args.join('-'); if (cache.has(key)) { console.log('Returning cached result...'); return cache.get(key); } else { const result = Reflect.apply(target, thisArg, args); cache.set(key, result); return result; } }, }); console.log(proxy(10, 0.2)); // Calculating cost... 12 console.log(proxy(10, 0.2)); // Returning cached result... 12 console.log(proxy(20, 0.2)); // Calculating cost... 24 console.log(proxy(20, 0.3)); // Calculating cost... 26 console.log(proxy(20, 0.3)); // Returning cached result... 26
En este ejemplo, definimos una función llamada calculateCost
que toma un precio y una tasa de impuestos y devuelve el costo con impuestos. Luego creamos un objeto de caché usando la clase Map
.
A continuación, creamos un objeto Proxy llamado proxy
que intercepta las llamadas a funciones usando la trampa apply
. La trampa apply
se llama cada vez que se llama a la función y recibe los argumentos de la función como una matriz. Usamos los argumentos para generar una clave de caché y verificar si el resultado ya está en el caché. Si es así, devolvemos el resultado almacenado en caché. De lo contrario, calculamos el resultado y lo almacenamos en el caché.
Finalmente, invocamos la función proxy
usando diferentes argumentos y observamos que el resultado se almacena en el caché para llamadas posteriores con argumentos idénticos.
Otro caso de uso de Proxy es validar propiedades de objetos. En este ejemplo, creamos un objeto Proxy que valida la longitud de una propiedad de cadena.
const user = { name: 'John', password: 'secret', }; const proxy = new Proxy(user, { set(target, prop, value) { if (prop === 'password' && value.length < 8) { throw new Error('Password must be at least 8 characters long'); } target[prop] = value; return true; }, }); console.log(proxy.name); // John console.log(proxy.password); // secret proxy.password = '12345678'; console.log(proxy.password); // 12345678 proxy.password = '123'; // Error
En este ejemplo, definimos un objeto llamado user
con una propiedad name
y password
. Luego creamos un objeto Proxy llamado proxy
que intercepta las asignaciones de propiedades usando la trampa set
. Se llama al set
trap cada vez que se asigna una propiedad y recibe el nombre de la propiedad, el nuevo valor y el objeto de destino.
Usamos la trampa set
para verificar si la propiedad que se está asignando es la propiedad password
y si el valor tiene menos de 8 caracteres. Si es así, lanzamos un error. De lo contrario, establecemos el valor de la propiedad en el objeto de destino.
Utilizamos el objeto proxy
para asignar varios valores a la propiedad password
y observamos que cualquier valor de menos de 8 caracteres genera un error.
Otro caso de uso común para Proxy es registrar accesos y asignaciones de propiedades de objetos. En este ejemplo, creamos un objeto Proxy que registra los accesos y asignaciones de propiedades.
const user = { name: 'John', email: '[email protected]', }; const proxy = new Proxy(user, { get(target, prop) { console.log(`Getting ${prop} property`); return target[prop]; }, set(target, prop, value) { console.log(`Setting ${prop} property to ${value}`); target[prop] = value; return true; }, }); console.log(proxy.name); // Getting name property -> John proxy.email = '[email protected]'; // Setting email property to [email protected] console.log(proxy.email); // Getting email property -> [email protected]
En este ejemplo, definimos un objeto llamado user
con un name
y una propiedad email
. A continuación, creamos un objeto Proxy llamado proxy
que intercepta los accesos y las asignaciones de propiedad utilizando las trampas get
y set
.
Se llama a get
trap cada vez que se accede a una propiedad, y recibe el nombre de la propiedad y el objeto de destino. En este ejemplo, registramos un mensaje en la consola que indica que se está accediendo a la propiedad y luego devolvemos el valor de la propiedad del objeto de destino.
Se llama al set
trap cada vez que se asigna una propiedad y recibe el nombre de la propiedad, el nuevo valor y el objeto de destino. En este ejemplo, registramos un mensaje en la consola que indica que se está asignando la propiedad y luego establecemos el valor de la propiedad en el objeto de destino.
Finalmente, accedemos y asignamos varias propiedades usando el objeto proxy
y observamos que los mensajes se registran en la consola.
Comportamiento personalizable : con los objetos proxy, puede interceptar y personalizar operaciones básicas en otros objetos, lo que le permite crear funciones avanzadas como control de acceso, almacenamiento en caché y registro.
Herencia : los objetos proxy ofrecen la capacidad de implementar patrones de herencia en JavaScript, lo que puede conducir a un código más versátil y escalable.
Revocable : los objetos proxy se pueden deshabilitar o revocar después de su creación, lo que los hace útiles para limitar el alcance del objeto proxy o por razones de seguridad.
A pesar de que el Proxy ha estado con nosotros durante mucho tiempo, no todas las versiones de los navegadores pueden admitir esta funcionalidad.
Además, el uso de Proxies puede afectar negativamente el rendimiento de su aplicación, especialmente si los usa con demasiada frecuencia.
Es importante entender el significado de usar un proxy. No se debe confiar en momentos críticos de la aplicación, como la validación importante de la entrada del usuario.
Tenga en cuenta las restricciones : antes de implementar un proxy en su código, tenga en cuenta las restricciones que impone y cómo pueden afectar la velocidad y la seguridad de su aplicación.
Los objetos proxy solo deben usarse cuando sea absolutamente esencial, ya que pueden afectar el rendimiento de su código.
Pruebe con cuidado : cuando utilice objetos Proxy, asegúrese de probar con cuidado y esté alerta a cualquier comportamiento potencialmente inesperado.
Adhiérase a las normas : para que su código sea fácil de leer y mantener, cumpla con las convenciones aceptadas y las mejores prácticas al implementar objetos Proxy.
El artículo profundiza en las funciones avanzadas de Proxy, como los patrones de herencia y la capacidad de crear objetos de Proxy revocables.
Independientemente de su nivel de experiencia como desarrollador, comprender Proxy en JavaScript es fundamental para elevar su código a un nivel superior.
Debido a su adaptabilidad y potencia, Proxy constituye un instrumento crítico para cualquier desarrollador de JavaScript que aspire a construir aplicaciones complejas con facilidad.