JavaScript Proxy y Reflect
Aprende cómo funcionan JavaScript Proxy y Reflect: intercepta operaciones get, set, apply, has y delete con traps, y aplica proxies para validación, control de acceso y registro.
Los proxies de JavaScript te permiten interceptar y redefinir las operaciones fundamentales sobre objects — leer una propiedad, escribirla, comprobar si existe una clave, llamar a una función, y más. Combinados con la API Reflect, que realiza esas mismas operaciones de forma "predeterminada", los proxies te ofrecen un mecanismo oficial y limpio para añadir comportamiento a los objects sin modificarlos directamente.
Este capítulo cubre qué es un proxy, los traps más comunes (get, set, apply, has, deleteProperty), cómo Reflect complementa a los proxies, y varios patrones prácticos como validación, control de acceso y registro.
Qué es un Proxy
Un Proxy envuelve un objeto target y un handler. El handler es un conjunto de funciones llamadas traps, cada una interceptando una operación específica. Cuando interactúas con el proxy, el trap correspondiente se ejecuta en lugar del comportamiento predeterminado; si no se define ningún trap para una operación, el proxy la reenvía al target sin cambios.
Esto es útil cuando quieres añadir comportamiento transversal — registro, validación, valores predeterminados, reglas de acceso — a un object sin tocar su propio código.
Sintaxis de Proxy
const proxy = new Proxy(target, handler);target: El object original cuyas operaciones quieres interceptar.handler: Un object cuyos métodos (traps) definen cómo se comportan las operaciones.
Luego usas proxy exactamente como usarías el object original; la diferencia es que tus traps se ejecutan en medio.
Comprendiendo el Trap get
El trap get intercepta las lecturas de propiedades sobre el object target. Recibe el target, la clave de property y el receiver (el propio proxy). Se usa frecuentemente para registrar accesos, calcular propiedades al vuelo, o devolver valores predeterminados para claves ausentes.
Ejemplo:
Este código configura un proxy para registrar los accesos a propiedades de un object.
- Handler: Define un trap
getpara registrar la propiedad accedida. - Object target: Contiene las propiedades
nameyage. - Proxy: Envuelve el object
targetcon elhandler.
Cuando se accede a proxy.name, registra "Getting name" y devuelve "John". Esto es útil para monitorizar o depurar accesos a propiedades.
Manipulando Operaciones de Object con los Traps set y apply
El Trap set
El trap set puede imponer reglas para las asignaciones de propiedades, asegurando que las propiedades contengan tipos específicos o cumplan ciertas condiciones.
Ejemplo:
Este código configura un proxy para validar y registrar las asignaciones de propiedades sobre un object.
- Handler: Define un trap
setpara comprobar la propiedadageen busca de valores válidos y registrar los intentos de asignarla. - Proxy: Envuelve el object
targetcon elhandler.
Cuando se asigna proxy.age, comprueba si es una edad válida (0-150). Si es inválida, registra un error y lanza una excepción.
El Trap apply
El método apply en un JavaScript Proxy intercepta las llamadas a funciones. Recibe tres argumentos:
- target: La función original que se está llamando.
- thisArg: El valor de
thisdentro de la función. - argumentsList: Un array de argumentos pasados a la función.
Ejemplo:
Este código configura un proxy para registrar las llamadas a funciones y sus argumentos.
- Handler: Define un trap
applypara registrar los argumentos cuando se llama a la función. - Función:
sumsuma dos números. - Proxy: Envuelve la función
sumcon elhandler.
En el código proporcionado, el trap apply registra los argumentos y luego llama a la función original usando target.apply(thisArg, argumentsList). Esto es útil para registro, depuración o modificación dinámica del comportamiento de funciones.
El Trap has
El trap has intercepta el operador in. Un uso común es ocultar claves "privadas" (por convención, nombres que comienzan con _) para que no parezcan existir desde el exterior.
Ejemplo:
Aunque _secret sigue existiendo en el target, el operador in devuelve false, por lo que la clave queda efectivamente oculta para el código que examina el object.
El Trap deleteProperty
El trap deleteProperty intercepta el operador delete, permitiéndote proteger ciertas claves de ser eliminadas. Debe devolver true cuando la eliminación está permitida, o lanzar un error para bloquearla en modo estricto.
Ejemplo:
Los proxies de JavaScript son poderosos, pero úsalos con criterio. El uso excesivo de proxies puede hacer que tu código sea más difícil de entender y mantener. Ten en cuenta que los proxies introducen una ligera sobrecarga de rendimiento en comparación con los objects nativos.
API Reflect
Reflect es un object integrado que proporciona un método para cada operación interceptable — el mismo conjunto exacto cubierto por los traps de proxy (Reflect.get, Reflect.set, Reflect.has, Reflect.deleteProperty, Reflect.apply, y así sucesivamente). Cada método realiza la versión predeterminada de esa operación.
Esto convierte a Reflect en el complemento natural de Proxy: dentro de un trap generalmente quieres añadir algún comportamiento y luego dejar que la operación proceda normalmente. Llamar al método Reflect correspondiente hace exactamente eso, y reenvía el receiver correctamente (importante para getters/setters), algo que un simple target[property] no hace. Verás este patrón utilizado en los ejemplos prácticos a continuación.
Los métodos Reflect también devuelven valores en lugar de lanzar excepciones — por ejemplo Reflect.set devuelve un boolean que indica éxito — lo que hace que las operaciones sean más predecibles que sus equivalentes de operador o Object.*.
Aquí tienes un recorrido rápido por los métodos clave de Reflect:
1. Reflect.get()
Este método se usa para obtener el valor de una propiedad de un object.
Ejemplo:
2. Reflect.set()
Este método se usa para establecer el valor de una propiedad en un object.
Ejemplo:
3. Reflect.has()
Este método comprueba si una propiedad existe en un object.
Ejemplo:
4. Reflect.deleteProperty()
Este método elimina una propiedad de un object.
Ejemplo:
5. Reflect.ownKeys()
Este método devuelve todas las claves de propiedades propias de un object.
Ejemplo:
6. Reflect.apply()
Este método llama a una función target con los argumentos dados.
Ejemplo:
7. Reflect.construct()
Este método se usa para crear una nueva instancia de un object.
Ejemplo:
Estos ejemplos muestran cómo puedes usar los métodos Reflect para realizar operaciones comunes sobre objects de una manera más limpia y consistente.
Casos de Uso Prácticos de los Proxies de JavaScript
Ejemplo 1: Inicialización Automática de Propiedades
Descripción: Usa los proxies de JavaScript para inicializar automáticamente propiedades undefined en un object. Esto puede ser útil en situaciones donde los objects se llenan dinámicamente con datos con el tiempo, como configuraciones de usuario o ajustes que pueden no estar definidos inicialmente.
Este código crea un proxy que comprueba si una propiedad existe en un object. Si no existe, el proxy establece automáticamente un valor predeterminado para ella. Esto ayuda a prevenir errores causados por propiedades ausentes.
Ejemplo 2: Control de Acceso
Descripción: Los proxies pueden imponer permisos de lectura o escritura sobre las propiedades de un object. Este ejemplo demuestra un proxy que impide que ciertas propiedades sean leídas o escritas en función de reglas predefinidas, lo que es especialmente útil para gestionar el acceso a datos sensibles.
Este código protege un object controlando el acceso a sus propiedades. Bloquea la lectura de 'sensitiveData' e impide modificar las propiedades 'readOnly', ayudando a mantener los datos seguros.
Ejemplo 3: Registro y Depuración
Descripción: Los proxies pueden usarse para registrar las interacciones con un object, lo que ayuda en la depuración y monitorización de operaciones. Este ejemplo crea un proxy que registra todos los gets, sets y llamadas a métodos realizados sobre un object.
Este código rastrea cada vez que alguien accede o cambia una propiedad del object, lo que es ideal para comprender qué hace tu código y cuándo.
Ejemplo 4: Validación de Datos
Descripción: Usa proxies para la validación al vuelo de las propiedades de un object. Esto es especialmente útil para garantizar la integridad de los datos cuando los objects se actualizan dinámicamente en una aplicación.
Este ejemplo demuestra cómo usar el Proxy de JavaScript para validar y registrar cambios de propiedades. El object validator comprueba si la propiedad age es un número válido entre 0 y 150. Si no lo es, registra un error y lanza una excepción. En caso contrario, registra el nuevo valor y actualiza la propiedad. El object person usa este validador para gestionar su propiedad age, asegurando que las edades inválidas sean detectadas y registradas.
Conclusión
Dominar los proxies de JavaScript te permite controlar y extender el comportamiento de los objects sin modificarlos directamente. Los proxies pueden imponer validación y reglas de acceso, proporcionar valores predeterminados, y potenciar herramientas de registro o depuración, mientras que Reflect mantiene las operaciones subyacentes limpias y predecibles. Usados con moderación, te ayudan a construir aplicaciones más dinámicas y seguras.
Para profundizar en las operaciones que interceptan los proxies, consulta getters y setters de propiedades y flags y descriptores de propiedades. Para el patrón de validación mostrado anteriormente, el manejo de errores con try...catch y las clases son complementos útiles.