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.