Command Palette

Search for a command to run...

Reflect.apply() y Reflect.construct() en JavaScript

Aprende a invocar funciones y constructores de forma programática con los métodos apply y construct de Reflect API.

Lectura: 12 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • Reflect.apply() invoca una función con un contexto this y argumentos específicos
  • Reflect.construct() crea instancias de constructores con argumentos variables
  • Ambos métodos son más consistentes que sus equivalentes en Function.prototype
  • Reflect.construct() permite especificar el prototipo de la instancia creada
  • Estos métodos son esenciales para implementar traps en Proxies

Introducción

Los métodos Reflect.apply() y Reflect.construct() son dos de las herramientas más poderosas de la API Reflect. Permiten invocar funciones y constructores de manera programática con un control preciso sobre el contexto de ejecución y los argumentos. Estos métodos son especialmente útiles en metaprogramación, donde necesitas manipular cómo se ejecutan las funciones sin modificar su código fuente.

Antes de ES6, invocar funciones con un contexto específico requería usar Function.prototype.apply() o Function.prototype.call(), y crear instancias de constructores dinámicamente era aún más complejo. Reflect simplifica estas operaciones proporcionando una API consistente y predecible.

Correspondencia con Proxy

Los métodos Reflect.apply() y Reflect.construct() corresponden directamente a los traps apply y construct de Proxy. Esta relación es fundamental cuando implementas Proxies que interceptan llamadas a funciones.

Reflect.apply()

Reflect.apply() invoca una función de destino con un valor this específico y argumentos proporcionados como un array. Es equivalente a Function.prototype.apply(), pero con una sintaxis más limpia y consistente con el resto de la API Reflect.

Sintaxis y Uso Básico

La firma de Reflect.apply() es: Reflect.apply(target, thisArg, argsArray). El primer parámetro es la función a invocar, el segundo es el valor de this dentro de la función, y el tercero es un array con los argumentos.

reflect-apply-basico.js
Loading code...

Este ejemplo muestra cómo Reflect.apply() te permite invocar funciones con un contexto de this explícito. Cuando pasas null como thisArg, la función se ejecuta en modo estricto con this como undefined, mientras que en modo no estricto this sería el objeto global.

Advertencia sobre thisArg

En modo estricto, pasar null o undefined como thisArg mantiene this como undefined. En modo no estricto, estos valores se convierten al objeto global, lo que puede causar comportamientos inesperados.

Control del Contexto this

Una de las ventajas más importantes de Reflect.apply() es el control preciso sobre el contexto de this. Esto es especialmente útil cuando trabajas con métodos que dependen de this para acceder a propiedades del objeto al que pertenecen.

reflect-apply-contexto.js
Loading code...

Este ejemplo demuestra cómo puedes invocar un método de un objeto en el contexto de otro objeto diferente. La función mostrarInfo accede a this.nombre y this.rol, y Reflect.apply() te permite controlar qué objeto se usa como this durante la ejecución.

Reflect.construct()

Reflect.construct() crea una nueva instancia de un constructor con argumentos proporcionados como un array. Es equivalente a usar el operador new, pero con la flexibilidad de especificar argumentos dinámicamente y controlar el prototipo de la instancia creada.

Sintaxis y Uso Básico

La firma básica de Reflect.construct() es: Reflect.construct(target, argsArray). También puedes especificar un tercer parámetro opcional newTarget que define el prototipo de la instancia creada.

reflect-construct-basico.js
Loading code...

Este ejemplo muestra cómo crear instancias de constructores dinámicamente usando Reflect.construct(). El primer parámetro es el constructor, el segundo es un array con los argumentos, y el resultado es una nueva instancia del objeto.

Ventaja sobre new

A diferencia del operador new, Reflect.construct() te permite especificar los argumentos como un array, lo que es ideal cuando los argumentos se generan dinámicamente o provienen de fuentes externas.

Especificando newTarget

El tercer parámetro newTarget de Reflect.construct() te permite controlar el prototipo de la instancia creada. Esto es útil cuando quieres crear instancias con un prototipo diferente al del constructor que ejecuta la inicialización.

reflect-construct-newtarget.js
Loading code...

En este ejemplo, usamos Persona para ejecutar la inicialización, pero especificamos Empleado como newTarget. Como resultado, la instancia tiene el prototipo de Empleado (por lo que tiene acceso a trabajar()), pero fue inicializada por el constructor de Persona.

Casos de Uso Avanzados

Los métodos Reflect.apply() y Reflect.construct() son especialmente útiles en escenarios de metaprogramación donde necesitas manipular cómo se ejecutan las funciones. Veamos algunos casos de uso prácticos:

  • <strong>Implementación de traps de Proxy:</strong> Usa Reflect.apply() dentro del trap apply para invocar la función original.
  • <strong>Invocación dinámica de métodos:</strong> Selecciona y ejecuta métodos basándote en condiciones en tiempo de ejecución.
  • <strong>Decoradores de funciones:</strong> Envuelve funciones con lógica adicional antes y después de su ejecución.
  • <strong>Fábricas de objetos:</strong> Crea instancias dinámicamente basándote en configuraciones o datos externos.
  • <strong>Testing y mocking:</strong> Simula el comportamiento de funciones y constructores en pruebas unitarias.

Estos patrones son comunes en librerías y frameworks que necesitan manipular el comportamiento de funciones sin modificar su código fuente.

reflect-apply-construct-casos.js
Loading code...

Este ejemplo muestra un decorador de funciones que usa Reflect.apply() para invocar la función original después de ejecutar lógica adicional. El decorador puede medir el tiempo de ejecución, agregar logging, o implementar cualquier otra funcionalidad transversal.

Patrón Decorator

Los decoradores son un patrón de diseño que te permite agregar funcionalidad a funciones o clases sin modificar su código. Reflect.apply() es ideal para implementar este patrón en JavaScript vanilla.

Resumen: Reflect.apply() y Reflect.construct()

Conceptos principales:

  • Reflect.apply() invoca funciones con contexto this explícito y argumentos como array
  • Reflect.construct() crea instancias de constructores con argumentos dinámicos
  • Ambos métodos corresponden a traps de Proxy (apply y construct)
  • Reflect.construct() permite especificar newTarget para controlar el prototipo
  • Son más consistentes que sus equivalentes en Function.prototype

Mejores prácticas:

  • Usa Reflect.apply() en traps de Proxy para invocar la función original
  • Especifica newTarget cuando necesites controlar el prototipo de la instancia
  • Prefiere Reflect.apply() sobre Function.prototype.apply() por consistencia
  • Usa estos métodos para implementar decoradores y fábricas de objetos
  • Ten cuidado con el valor de thisArg en modo no estricto