Command Palette

Search for a command to run...

Traps deleteProperty y has: Interceptando Eliminaciones y Verificaciones en Proxy

Aprende a usar los traps deleteProperty y has de Proxy para controlar la eliminación de propiedades y personalizar el operador in, implementando protección de datos y validación de existencia.

Lectura: 14 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • El trap deleteProperty intercepta el operador delete (delete obj.propiedad)
  • El trap has intercepta el operador in ('propiedad' in obj)
  • Ambos traps permiten implementar protección de propiedades y control de acceso
  • deleteProperty debe devolver true si la eliminación fue exitosa o false si falló
  • has debe devolver true si la propiedad existe o false si no existe

Introducción a Traps deleteProperty y has

Los traps deleteProperty y has complementan los traps get y set, permitiéndote interceptar operaciones adicionales sobre objetos. El trap deleteProperty se ejecuta cuando intentas eliminar una propiedad usando el operador delete, mientras que el trap has se ejecuta cuando verificas si una propiedad existe usando el operador in.

Estos traps son especialmente útiles para implementar protección de datos, control de acceso y validación de operaciones. Puedes prevenir la eliminación de propiedades críticas, ocultar propiedades internas, o implementar lógica personalizada para determinar si una propiedad "existe" según ciertos criterios.

  • Prevenir la eliminación de propiedades críticas o de configuración
  • Implementar propiedades ocultas que no aparecen en el operador in
  • Validar que solo ciertos usuarios puedan eliminar propiedades específicas
  • Crear propiedades virtuales que aparecen como existentes pero no están en el objeto
  • Implementar logging de todas las operaciones de eliminación y verificación

Diferencia con Object.defineProperty()

Para prevenir la eliminación de propiedades, también puedes usar Object.defineProperty() con configurable: false. Sin embargo, Proxy ofrece más flexibilidad porque puedes implementar lógica condicional (por ejemplo, permitir eliminación solo en ciertas circunstancias) y aplicar la misma lógica a múltiples propiedades sin definirlas una por una.

Trap deleteProperty: Interceptando Eliminaciones

El trap deleteProperty se ejecuta cada vez que intentas eliminar una propiedad usando el operador delete. Recibe dos parámetros: el target (el objeto original) y la propiedad que se está eliminando (como string o Symbol). El trap debe devolver true si la eliminación fue exitosa, o false si falló.

Dentro del trap deleteProperty, puedes implementar cualquier lógica antes de permitir la eliminación. Puedes verificar que la propiedad pueda ser eliminada, registrar la operación, o lanzar un error si la propiedad está protegida. Si lanzas un error dentro del trap, la eliminación falla y el error se propaga.

Uso Básico del Trap deleteProperty

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

deleteproperty-basico.js
Loading code...

El trap deleteProperty intercepta todas las eliminaciones de propiedades. En este ejemplo, simplemente registramos qué propiedad se está eliminando y luego usamos Reflect.deleteProperty para eliminarla del target original.

Protección de Propiedades Críticas

Una de las aplicaciones más comunes del trap deleteProperty es proteger propiedades críticas que no deben ser eliminadas. Puedes definir una lista de propiedades protegidas y prevenir su eliminación lanzando un error.

proteccion-propiedades.js
Loading code...

Este ejemplo muestra cómo proteger propiedades críticas de la eliminación. Las propiedades id, createdAt y version están protegidas y no pueden ser eliminadas. Si intentas eliminarlas, se lanza un error específico que describe el problema.

Mejor Práctica: Nombres de Propiedades Protegidas

Usa una convención de nombres para las propiedades protegidas, como prefijarlas con un guion bajo (_propiedad) o usar nombres descriptivos (id, createdAt, version). Esto hace el código más claro y ayuda a otros desarrolladores a entender qué propiedades no deben ser modificadas.

Trap has: Interceptando el Operador in

El trap has se ejecuta cada vez que verificas si una propiedad existe usando el operador in. Recibe dos parámetros: el target (el objeto original) y la propiedad que se está verificando (como string o Symbol). El trap debe devolver true si la propiedad existe, o false si no existe.

El trap has es especialmente útil para implementar propiedades ocultas o virtuales. Puedes hacer que ciertas propiedades no aparezcan en el operador in, o hacer que propiedades virtuales aparezcan como existentes aunque no estén en el objeto original.

Uso Básico del Trap has

Este ejemplo muestra cómo usar el trap has para interceptar todas las verificaciones de existencia de propiedades y agregar logging. El trap recibe la propiedad y usa Reflect.has para verificar si existe en el target original.

has-basico.js
Loading code...

El trap has intercepta todas las verificaciones de existencia usando el operador in. En este ejemplo, simplemente registramos qué propiedad se está verificando y luego usamos Reflect.has para verificar si existe en el target original.

Propiedades Ocultas

Puedes usar el trap has para ocultar propiedades internas que no deberían ser accesibles desde fuera del objeto. Esto es útil para implementar encapsulación y proteger datos internos.

propiedades-ocultas.js
Loading code...

Este ejemplo muestra cómo ocultar propiedades internas usando el trap has. Las propiedades que empiezan con un guion bajo (_password, _token) no aparecen en el operador in, aunque siguen siendo accesibles directamente si conoces su nombre.

Encapsulación con Proxy

Los traps has y get pueden trabajar juntos para implementar encapsulación completa. Usa has para ocultar propiedades internas del operador in, y usa get para prevenir el acceso directo a esas propiedades. Sin embargo, recuerda que esto no es seguridad real: las propiedades siguen existiendo en el objeto y pueden ser accedidas si se conoce su nombre.

Propiedades Protegidas

Las propiedades protegidas son propiedades que no pueden ser eliminadas ni modificadas. Puedes implementar este patrón usando los traps deleteProperty y set juntos para prevenir cualquier modificación de propiedades críticas.

propiedades-protegidas-completas.js
Loading code...

Este ejemplo muestra cómo implementar propiedades completamente protegidas que no pueden ser eliminadas ni modificadas. Los traps deleteProperty y set trabajan juntos para prevenir cualquier modificación de las propiedades protegidas.

Validación de Existencia de Propiedades

El trap has también puede usarse para implementar validación de existencia de propiedades. Puedes hacer que propiedades virtuales aparezcan como existentes, o implementar lógica personalizada para determinar si una propiedad "existe" según ciertos criterios.

validacion-existencia.js
Loading code...

Este ejemplo muestra cómo implementar propiedades virtuales que aparecen como existentes en el operador in. Las propiedades fullName y ageInDays se calculan dinámicamente y aparecen como si existieran en el objeto, aunque no estén definidas en el target original.

Propiedades Virtuales vs Getters

Las propiedades virtuales implementadas con el trap has son diferentes de los getters tradicionales. Los getters solo funcionan para propiedades que accedes directamente, mientras que las propiedades virtuales con has aparecen en el operador in, en Object.keys(), y en otras operaciones que enumeran propiedades. Esto las hace más transparentes para el código que consume el objeto.

Errores Comunes

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

Error: No Devolver true en deleteProperty

El trap deleteProperty debe devolver true si la eliminación fue exitosa, o false si falló. Si olvidas devolver un valor explícitamente, JavaScript puede interpretar esto como una operación fallida.

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

Este ejemplo muestra el problema de no devolver true en el trap deleteProperty. En modo estricto, si el trap deleteProperty no devuelve true, JavaScript lanza un TypeError. Siempre asegúrate de devolver el resultado de Reflect.deleteProperty, que ya devuelve true o false según el resultado de la operación.

Por Qué Devolver true

El operador delete devuelve true si la propiedad fue eliminada exitosamente, o false si no. Si el trap deleteProperty no devuelve un valor truthy, JavaScript asume que la operación falló. Siempre devuelve el resultado de Reflect.deleteProperty para garantizar el comportamiento correcto.

Error: Bucle Infinito en has

Un error común es crear un bucle infinito dentro del trap has. Esto ocurre cuando el trap intenta verificar la propiedad usando el operador in en lugar de Reflect.has, lo que hace que el trap se ejecute recursivamente.

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

Este ejemplo muestra cómo crear accidentalmente un bucle infinito. Dentro del trap has, usamos el operador in para verificar si la propiedad existe en el target. Como target no es un Proxy, esto no causa un bucle infinito en este caso, pero si target fuera un Proxy, causaría un bucle infinito. Siempre usa Reflect.has para verificar la existencia de propiedades.

Error: Comportamiento Inconsistente

Otro error común es implementar un comportamiento inconsistente entre los traps deleteProperty y has. Por ejemplo, permitir que una propiedad sea eliminada pero hacer que siga apareciendo en el operador in.

error-inconsistent-delete.js
Loading code...

Este ejemplo muestra un comportamiento inconsistente. La propiedad edad puede ser eliminada con delete, pero sigue apareciendo en el operador in debido al trap has que siempre devuelve true para propiedades específicas. Esto puede causar confusión y bugs difíciles de debuggear.

Resumen: Traps deleteProperty y has

Conceptos principales:

  • El trap deleteProperty intercepta el operador delete (delete obj.propiedad)
  • El trap has intercepta el operador in ('propiedad' in obj)
  • Ambos traps permiten implementar protección de propiedades y control de acceso
  • deleteProperty debe devolver true si la eliminación fue exitosa
  • has debe devolver true si la propiedad existe o false si no existe

Mejores prácticas:

  • Usa siempre Reflect.deleteProperty y Reflect.has dentro de los traps
  • Implementa protección para propiedades críticas que no deben ser eliminadas
  • Usa convenciones de nombres para propiedades protegidas y ocultas
  • Mantén un comportamiento consistente entre deleteProperty y has
  • Asegúrate de devolver true o false explícitamente en ambos traps