Proxies ES6 en la práctica

Con la aparición de ECMAScript 2015, se produjo una avalancha de características; algunos de ellos te vuelven loco, y otros son sorpresas agradables, como conocer a un viejo amigo después de mucho tiempo.


Algunas características están relacionadas con la metaprogramación. Que es eso No soy muy elocuente, así que pasemos a nuestro amigo, Wikipedia.


La metaprogramación es una técnica de programación en la cual los programas de computadora tienen la capacidad de tratar a otros programas como sus datos. Significa que un programa puede diseñarse para leer, generar, analizar o transformar otros programas e incluso modificarse a sí mismo mientras se ejecuta. En algunos casos, esto permite a los programadores minimizar la cantidad de líneas de código para expresar una solución, lo que a su vez reduce el tiempo de desarrollo. También permite a los programas una mayor flexibilidad para manejar eficientemente nuevas situaciones sin recompilación.

En pocas palabras, la metaprogramación permite que un programa manipule a otros o a sí mismos tanto en tiempo de compilación como de ejecución. La metaprogramación en JavaScript se basa en dos características: Proxy y Reflect API. En este post, consideraremos el primero.


Proxy


Proxy es una nueva API que permite interceptar, modificar y extender objetos en tiempo de ejecución. Usando esta API, puedes:


  • Perfiles y registros de depuración,
  • Interceptar llamadas a propiedades,
  • Validar "sobre la marcha",
  • etc.

Proxy es un constructor que acepta dos parámetros: objeto fuente y objeto que actúa como un controlador para el objeto fuente. Este último contiene métodos que se conocen como trampas.



Una trampa es un método que modifica el comportamiento de alguna parte del objeto. Por ejemplo, la trampa obtiene y establece intercepta las llamadas a las propiedades para obtener y establecer un valor respectivamente, pudiendo colocar la lógica antes y durante este proceso.


Para comprender mejor la utilidad de los poderes, hagamos algunos ejercicios pequeños.


Ejemplo: registro / perfilado


Imagínese, tiene 17 años, ya está a punto de cumplir 18 años. Y desea que su programa lo felicite automáticamente cuando lo abra. Para esto, puedes usar Proxy.


et person = { name: "John Doe", age: 17 }; person = new Proxy(person, { set(target, property, value) { if (value === 18) { console.log("Congratulations! You are of legal age"); Reflect.set(target, property, value); return true; } } }); person.age = 18; Not only can we do logs, as I said at the beginning, we can do as far as the language limits us. Here we could make validations for the age, for example, if it exceeds 100 that throw us an error: if (value < 13 && value > 99) { throw new Error('The age should be between 13 and 99') } else { Reflect.set(target, property, value) } Example: secure access to properties let person = { name: "John Doe" }; const Undefined = new Proxy( {}, { get(target, name, receiver) { return Undefined; } } ); const Safeish = obj => { return new Proxy(obj, { get(target, property, receiver) { if (target.hasOwnProperty(property)) { const isObject = target[property] instanceof Object; return isObject ? Safeish(target[property]) : Reflect.get(target, property, receiver); } return Undefined; } }); }; person = Safeish(person); console.log(person.name); console.log(person.sister.name === Undefined); 

Ejemplo: matriz de consultas


Ya hemos visto un ejemplo, con las trampas get y set más utilizadas. Para reforzar, vayamos un poco más lejos y usemos proxies anidados. Este ejercicio intentará convertir una matriz convencional en una matriz consultable para usar operadores como el clásico SQL groupBy.


Para esto, necesitaremos dos parámetros de entrada:


  • colección: conjunto de objetos que ampliaremos.
  • groupKeys: conjunto de cadenas que representan las propiedades para las que vas a agrupar (nombre, categoría, precio, etc.)

 const data = [ { id: 1, category: 2, name: "Intel NUC Hades Canyon" }, { id: 2, category: 1, name: "Logitech K380" }, { id: 3, category: 1, name: "Genius ECO-8100" } ]; const groupable = (collection, groupKeys) => { // Check that the collection is an array if (!(collection instanceof Array)) { throw new TypeError("The input collection is not an Array"); } const data = JSON.parse(JSON.stringify(collection)); const clone = JSON.parse(JSON.stringify(collection)); Object.defineProperty(clone, "groupBy", { configurable: true, enumerable: false, writable: false, value: groupKeys.reduce((acc, cur) => { acc[cur] = null; return acc; }, {}) }); 

  return new Proxy(clone, { get(target, property, receiver) { if (property === "groupBy") { return new Proxy(target[property], { get(target, property, receiver) { // if the property to be grouped does not exist // log a warning and return [] if (!target.hasOwnProperty(property)) { return []; } // Otherwise, group by property return data.reduce(function(acc, cur) { (acc[cur[property]] = acc[cur[property]] || []).push(cur); return acc; }, {}); } }); } return Reflect.get(target, property, receiver); } }); }; const datasource = groupable(data, ["category"]); console.log(datasource.groupBy.category); 

Conclusiones


El Proxy puede no ser la función ES6 más utilizada, pero junto con Reflect API, es una de las más importantes e interesantes. Su flexibilidad permite adoptarlo en una multitud de casos y, lo mejor de todo, es fácil de implementar.


Referencias


https://es.wikipedia.org/wiki/Metaprogramaci%C3%B3n

Source: https://habr.com/ru/post/448214/


All Articles