Cómo los Proxies en JavaScript nos permiten interceptar y personalizar el comportamiento de los objetos.
A veces, trabajando con objetos en JavaScript, nos puede interesar tener un poco más de control sobre cómo se accede o se modifican sus propiedades. Quizá necesitemos validar datos, registrar accesos o incluso devolver un valor predeterminado si una propiedad no existe. Para estas situaciones, JavaScript nos ofrece una característica interesante: los Proxies.
Pensemos en un Proxy como un intermediario o una envoltura alrededor de un objeto ‘real’. Este intermediario puede interceptar operaciones que normalmente irían directas al objeto, permitiéndonos ejecutar nuestro propio código antes, después, o incluso en lugar de la operación original.
La idea central es bastante clara. Creamos un Proxy usando new Proxy(target, handler)
. El target
es nuestro objeto original, y el handler
es un objeto especial que define qué operaciones queremos interceptar y cómo. Estas ‘intercepciones’ se llaman traps (trampas).
Por ejemplo, si queremos hacer algo especial cuando alguien intenta leer una propiedad, usamos la trampa get
en el handler
. Veamos un caso donde devolvemos un mensaje si accedemos a la propiedad de un objeto que no existe:
const handlerGet = { get(target, prop) { // Comprobamos si la propiedad existe en el objeto original (target) if (prop in target) { return target[prop]; // Devolvemos el valor original } else { // Si no existe, devolvemos un mensaje personalizado // Usamos el ejemplo que nos diste originalmente return `La propiedad "${prop}" no existe.`; } }};
const objetoOriginal = { nombre: "Documento Importante" };// Creamos un proxy vacío inicialmente para demostrar el mensaje de "no existe"const proxyInicialVacio = new Proxy({}, handlerGet);console.log(proxyInicialVacio.nombre); // Output: La propiedad "nombre" no existe.
// Ahora, usemos el objeto real como targetconst proxyConTarget = new Proxy(objetoOriginal, handlerGet);console.log(proxyConTarget.nombre); // Output: Documento Importanteconsole.log(proxyConTarget.fecha); // Output: La propiedad "fecha" no existe.
En este código, nuestro handlerGet
intercepta cualquier intento de lectura. Si la propiedad existe en el target
, la devuelve; si no, devuelve nuestro mensaje personalizado. Es una forma sencilla de manejar accesos a propiedades indefinidas.
De manera similar, podemos interceptar la escritura de propiedades con la trampa set
. Esto es muy útil para validaciones. Imaginemos que queremos asegurarnos de que una propiedad cantidad
siempre sea un número mayor que cero.
const handlerSet = { set(target, prop, value) { if (prop === 'cantidad') { if (typeof value !== 'number' || value <= 0) { console.warn('¡Atención! La cantidad debe ser un número positivo.'); // Indicamos que la asignación no se realizó devolviendo false. return false; } } // Si la validación pasa (o no es la propiedad 'cantidad'), // realizamos la asignación en el objeto original. // Usamos Reflect.set para asegurar el comportamiento correcto. Reflect.set(target, prop, value); // Indicamos que la asignación fue exitosa. return true; }};
const producto = { nombre: "Tornillos" };const proxyValidador = new Proxy(producto, handlerSet);
proxyValidador.cantidad = 50; // Funcionaconsole.log(producto.cantidad); // Output: 50
proxyValidador.cantidad = -10; // Output: ¡Atención! La cantidad debe ser un número positivo.console.log(producto.cantidad); // Output: 50 (no cambió)
proxyValidador.cantidad = "muchos"; // Output: ¡Atención! La cantidad debe ser un número positivo.console.log(producto.cantidad); // Output: 50 (no cambió)
Aquí, el handlerSet
verifica si la propiedad es cantidad
y si el valor cumple nuestra condición. Si no, muestra un aviso y evita la asignación, devolviendo false
.
Existen más trampas disponibles; podemos interceptar la comprobación de existencia de propiedades (has
), la eliminación (deleteProperty
), llamadas a funciones si el target es una función (apply
), la creación de instancias si el target es un constructor (construct
), y varias otras operaciones sobre los objetos.
El proxy en JavaScript es un concepto avanzado del lenguaje que permite añadir funcionalidades complejas sobre objetos. Entre ellas:
Los Proxies son una herramienta que nos da un control avanzado sobre cómo interactuamos con los objetos en JavaScript. Son muy útiles para tareas específicas como las que mencionamos y nos permiten añadir lógica ‘por encima’ del comportamiento normal de un objeto sin tener que modificar su estructura interna directamente, lo cual ayuda a mantener nuestro código más organizado y separado por responsabilidades.