ES6 Proxies en práctica
Tags: javascript, proxy, webdev
Published: 2019-03-12 19:33:55

Con la aparición de ECMAScript 2015 (aka ES6), vino una avalancha de _features_; unas que ya se venían pidiendo a gritos desconsolados y desgarradores, y otros que fueron gratas sorpresillas, como cuando te encuentras a un viejo amigo mucho tiempo después.

Una de las features -del último grupo descrito- son las relacionadas a la _metaprogramación_. ¿Qué es eso? No ando muy elocuente hoy, así que vayamos a nuestra infalible amiga, _la_ Wikipedia.

> La metaprogramación consiste en escribir programas que escriben o manipulan otros programas (o a sí mismos) como datos, o que hacen en tiempo de compilación parte del trabajo que, de otra forma, se haría en tiempo de ejecución. Esto permite al programador ahorrar tiempo en la producción de código.

Podemos entender por _metaprogramación_ como la capacidad de que un programa manipule otros o a sí mismos tanto en tiempo de compilación como de ejecución. Esta capacidad ha sido añadida a los lenguajes de programación prácticamente desde sus inicios y ahora también la tenemos disponible en el lenguaje bandera de la web: JavaScript.

La _metaprogramación_ en JavaScript se basa en dos features: **Proxy** y **Reflect API**. En esta publicación trataremos el primero.

## Proxy

Proxy es una nueva API que nos permite interceptar, modificar y extender objetos en tiempo de ejecución. Tan simple como eso; a través de esta API podemos realizar cosas como:

- Profiling y logs de depuración.
- Intercepción de llamadas a propiedades.
- Validaciones _"on the fly"_.

Entre otras muchas.

Proxy es un constructor que acepta dos parámetros: el objeto origen, un objeto que actúa como handler para el objeto origen. Este último contiene métodos que son conocidos como **Traps**.

Un *Trap* es un método**que modifica el comportamiento** de alguna parte del objeto. Por ejemplo, el trap `get` y `set` interceptan las llamadas a propiedades para obtener y establecer un valor respectivamente, pudiendo colocar lógica antes y durante este proceso.

> Puedes ver la lista completa de *traps* [aquí](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Proxy#M%C3%A9todos_del_objeto_handler).

Para entender mejor la utilidad de los proxies, hagamos unos pequeños ejercicios.

---

### Ejemplo: logging/profiling

Aún tenemos 17 años, estamos en la flor de nuestra adolescencia, ~~haciendo apología al sexo, a los cigarrillos y al alcohol~~ en plena era de aprendizaje y vivencia de nuevas experiencias. Estamos por cumplir los 18 años ya, y queremos que nuestro programa nos felicite automáticamente al cumplirlos 🎉. Para esto, podemos hacer uso de un Proxy.

{% codesandbox 103rpp07l4 %}

No solo podemos hacer logs, como dije en un principio, podemos hacer hasta donde el lenguaje nos limite. Aquí pudimos hacer validaciones para la edad, por ejemplo, si pasa de 100 que nos arroje un error:

```javascript
if (value < 13 && value > 99) {
  throw new Error('La edad debe ser entre 13 y 99')
} else {
  Reflect.set(target, property, value)
}
```

### Ejemplo: acceso seguro a propiedades

{% codesandbox znpq440r23 %}

### Ejemplo: query array

Ya vimos un ejemplo, con los traps `get` y `set`, que son los que más se usan. Para reforzar, vamos a ir un poco más allá y usaremos proxies anidados. Este ejercicio tratará de convertir un array convencional a uno _queryable_, para usar operadores útiles como el clásico **groupBy** de SQL.

Para esto, necesitaremos dos parámetros de entrada:

- `collection`: array de objetos el cual extenderemos.
- `groupKeys`: array de strings que representan las propiedades por las cual se va a agrupar (name, category, price, etc.)


{% codesandbox j322xkqm89 %}

---

## Conclusiones

Los Proxy quizás no sea una de las más usadas features de ES6, pero es sin duda, junto con Reflect API, una de las más importantes e interesantes. Su flexibilidad nos permite adoptarla en multitud de casuísticas y lo mejor, es fácil de implementar.