Command Palette

Search for a command to run...

Traps get y set: Interceptando Lecturas y Escrituras en Proxy

Domina los traps get y set de Proxy para controlar el acceso a propiedades, implementar validación, reactividad y propiedades virtuales en JavaScript.

Lectura: 15 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • El trap get intercepta todas las operaciones de lectura de propiedades (obj.prop y obj['prop'])
  • El trap set intercepta todas las operaciones de escritura de propiedades (obj.prop = valor)
  • Ambos traps reciben el receiver como cuarto parámetro, que es el objeto o Proxy que inició la operación
  • Usa Reflect.get y Reflect.set dentro de los traps para realizar las operaciones originales de forma consistente
  • Los traps get y set son la base para implementar reactividad, validación, logging y propiedades computadas

Introducción a Traps get y set

Los traps get y set son los dos traps más utilizados en Proxy porque interceptan las operaciones más comunes sobre objetos: la lectura y escritura de propiedades. Cada vez que accedes a una propiedad usando notación de punto (obj.propiedad) o notación de corchetes (obj['propiedad']), se ejecuta el trap get. Similarmente, cada vez que asignas un valor a una propiedad, se ejecuta el trap set.

Estos traps te permiten implementar patrones de diseño avanzados sin modificar el objeto original. Puedes agregar validación automática, implementar reactividad similar a frameworks modernos, crear propiedades virtuales que no existen en el objeto original, y mucho más.

  • Validación de tipos y valores antes de permitir la asignación
  • Implementación de propiedades computadas que se calculan dinámicamente
  • Logging y debugging de todas las operaciones de acceso a propiedades
  • Control de acceso basado en permisos o roles de usuario
  • Implementación de reactividad para actualizaciones automáticas de UI

Diferencia con Getters/Setters

Los traps get y set de Proxy son más potentes que los getters y setters tradicionales de ES5 porque interceptan TODAS las operaciones de lectura y escritura, incluyendo propiedades que no existen en el objeto original. Los getters/setters solo funcionan para propiedades específicas que hayas definido previamente.

Trap get: Interceptando Lecturas

El trap get se ejecuta cada vez que lees una propiedad de un Proxy. Recibe tres parámetros: el target (el objeto original), la propiedad que se está accediendo (como string o Symbol), y el receiver (el objeto o Proxy que inició la operación). El receiver es importante porque permite que el trap funcione correctamente con Proxies anidados y herencia.

Dentro del trap get, puedes implementar cualquier lógica antes de devolver el valor. Puedes validar que la propiedad exista, transformar el valor, implementar propiedades virtuales, o incluso devolver valores diferentes según el contexto de la llamada.

Uso Básico del Trap get

Este ejemplo muestra cómo usar el trap get para interceptar todas las lecturas de propiedades y agregar logging. El trap recibe la propiedad y usa Reflect.get para obtener el valor del target original.

get-basico.js
Loading code...

El trap get intercepta todas las lecturas de propiedades, incluyendo las que usan notación de corchetes. En este ejemplo, simplemente registramos qué propiedad se está accediendo y luego usamos Reflect.get para obtener el valor del target original.

Propiedades Virtuales con get

Una de las características más poderosas del trap get es la capacidad de crear propiedades virtuales: propiedades que no existen en el objeto original pero que se comportan como si existieran. Esto es útil para implementar propiedades computadas, valores derivados o propiedades que se calculan dinámicamente.

propiedades-virtuales.js
Loading code...

Este ejemplo muestra cómo crear propiedades virtuales que no existen en el objeto original. Las propiedades nombreCompleto y edadEnDias se calculan dinámicamente cada vez que se acceden, mientras que las propiedades reales (nombre, apellido, edad) se obtienen del target original.

Mejor Práctica: Nombres de Propiedades Virtuales

Usa un prefijo o sufijo para distinguir las propiedades virtuales de las propiedades reales. Por ejemplo, usa getNombreCompleto() para métodos o nombreCompleto para propiedades computadas. Esto hace el código más claro y evita confusiones.

Trap set: Interceptando Escrituras

El trap set se ejecuta cada vez que asignas un valor a una propiedad de un Proxy. Recibe cuatro parámetros: el target, la propiedad que se está modificando, el nuevo valor, y el receiver. El trap debe devolver true si la asignación fue exitosa, o false si falló. Si lanzas un error dentro del trap, la asignación falla y el error se propaga.

El trap set es ideal para implementar validación de datos. Puedes verificar que el valor cumpla ciertas condiciones antes de permitir la asignación. Si la validación falla, puedes lanzar un error específico o devolver false para indicar que la operación no fue exitosa.

Validación de Datos con set

El trap set es ideal para validar datos antes de permitir la asignación. Puedes verificar formatos, tipos o rangos de valores, y lanzar errores descriptivos cuando la validación falle.

validacion-con-set.js
Loading code...

Este ejemplo valida el formato de email usando una expresión regular. Si el email no cumple el formato esperado, el trap lanza un error antes de que el valor se asigne al objeto. Las asignaciones válidas se delegan a Reflect.set para que funcionen normalmente.

Inmutabilidad con set

El trap set también permite crear objetos inmutables que rechacen cualquier intento de modificación. Esto es útil para proteger configuraciones o constantes que no deben cambiar durante la ejecución.

inmutabilidad-con-set.js
Loading code...

El trap set lanza un error para cualquier intento de modificación, garantizando que el objeto permanezca inalterado. Las lecturas funcionan normalmente, solo las escrituras están bloqueadas. Esto es más flexible que Object.freeze() porque puedes implementar lógica condicional si fuera necesario.

Alternativa: Object.freeze()

Para inmutabilidad simple, Object.freeze(obj) congela el objeto y previene modificaciones. Sin embargo, Proxy ofrece más flexibilidad porque puedes personalizar el mensaje de error o implementar reglas más complejas sobre qué propiedades son inmutables.

Propiedades Virtuales Avanzadas

Las propiedades virtuales pueden ser más complejas y calcular valores derivados de múltiples propiedades. Combinando get y set, puedes crear propiedades computadas de solo lectura que se recalculan automáticamente cuando cambian sus dependencias.

propiedades-virtuales-avanzado.js
Loading code...

Este ejemplo calcula subtotal y total dinámicamente basándose en precio, cantidad y tasa de IVA. Las propiedades virtuales se recalculan automáticamente cuando cambias precio o cantidad. El trap set previene que intentes modificar directamente las propiedades calculadas, lanzando un error si lo intentas.

Implementando Reactividad

La reactividad es un patrón donde las actualizaciones de datos desencadenan automáticamente otras acciones. El trap set puede detectar cambios en propiedades y ejecutar callbacks, permitiéndote actualizar la UI, recalcular valores o enviar notificaciones automáticamente.

reactividad-basica.js
Loading code...

Este ejemplo crea un sistema de reactividad simple. Cada vez que modificas una propiedad, el trap set compara el valor anterior con el nuevo, y si son diferentes, ejecuta el callback con la información del cambio. Si asignas el mismo valor, el callback no se ejecuta, optimizando el rendimiento.

Aplicaciones de Reactividad

Este patrón es la base de muchos sistemas de gestión de estado en JavaScript. Puedes usarlo para sincronizar datos con LocalStorage, actualizar elementos del DOM automáticamente, o implementar observadores de cambios para debugging y logging.

Errores Comunes

Al trabajar con los traps get y set, hay varios errores comunes que debes evitar. Estos errores pueden causar comportamientos inesperados, bugs difíciles de debuggear o problemas de rendimiento.

Error: Olvidar Usar Reflect

Un error común es acceder directamente a target[prop] en lugar de usar Reflect. Aunque funciona en casos simples, puede causar problemas con getters/setters, herencia y Proxies anidados.

error-olvidar-reflect.js
Loading code...

Ambos enfoques funcionan para casos simples, pero Reflect garantiza comportamiento consistente con el lenguaje. Reflect.get y Reflect.set manejan correctamente la cadena de prototipos, getters/setters personalizados y el parámetro receiver para Proxies anidados. Siempre usa Reflect para evitar bugs sutiles.

Por Qué Usar Reflect

Reflect.get y Reflect.set son equivalentes funcionales a las operaciones nativas de JavaScript, pero diseñadas específicamente para usarse dentro de traps de Proxy. Garantizan que el comportamiento sea idéntico al de las operaciones normales, especialmente con getters/setters y herencia.

Error: Bucle Infinito

Acceder al receiver dentro de un trap crea un bucle infinito. Como receiver es el Proxy mismo, acceder a receiver[prop] vuelve a ejecutar el trap, que vuelve a acceder al receiver, causando "Maximum call stack size exceeded".

error-bucle-infinito.js
Loading code...

El error ocurre porque receiver es el Proxy, no el target. Cuando el trap get accede a receiver[prop], ejecuta el trap get nuevamente, causando recursión infinita. La solución es usar Reflect.get(target, prop, receiver) que accede al target pero mantiene el contexto del receiver para la cadena de prototipos.

Error: No Devolver true en set

El trap set debe devolver true si la operación fue exitosa. Si devuelves undefined (o no devuelves nada), en modo estricto JavaScript lanza un TypeError indicando que el trap devolvió un valor falsy.

error-no-devolver-true.js
Loading code...

En modo estricto, si el trap set no devuelve true, obtienes un TypeError. La solución es devolver el resultado de Reflect.set, que siempre devuelve true cuando la asignación tiene éxito. Esto garantiza que el comportamiento sea consistente con las asignaciones normales de JavaScript.

Resumen: Traps get y set

Conceptos principales:

  • El trap get intercepta todas las lecturas de propiedades (obj.prop y obj['prop'])
  • El trap set intercepta todas las escrituras de propiedades (obj.prop = valor)
  • Ambos traps reciben el receiver como parámetro para manejar Proxies anidados correctamente
  • Las propiedades virtuales se calculan dinámicamente y no existen en el objeto original
  • La reactividad se implementa detectando cambios en propiedades y ejecutando observadores

Mejores prácticas:

  • Usa siempre Reflect.get y Reflect.set dentro de los traps para comportamiento consistente
  • Implementa validación en el trap set para prevenir asignaciones de valores inválidos
  • Usa prefijos para distinguir propiedades virtuales de propiedades reales
  • Evita acceder al receiver dentro de los traps para prevenir bucles infinitos
  • Asegúrate de devolver true en el trap set cuando la operación sea exitosa