Proxies ES6 na prática

Com o surgimento do ECMAScript 2015, chegou uma avalanche de recursos; alguns deles deixam você louco, e outros são surpresas agradáveis, como conhecer um velho amigo depois de um longo tempo.


Alguns recursos estão relacionados à metaprogramação. O que é isso? Eu não sou muito eloquente, então vamos ao nosso amigo, Wikipedia.


A metaprogramação é uma técnica de programação na qual os programas de computador podem tratar outros programas como dados. Isso significa que um programa pode ser projetado para ler, gerar, analisar ou transformar outros programas e até mesmo se modificar durante a execução. Em alguns casos, isso permite que os programadores minimizem o número de linhas de código para expressar uma solução, reduzindo o tempo de desenvolvimento. Também permite aos programas maior flexibilidade para lidar com novas situações com eficiência, sem recompilação.

Em poucas palavras, a metaprogramação permite que um programa manipule os outros ou a si mesmos no tempo de compilação e execução. A metaprogramação em JavaScript é baseada em dois recursos: Proxy e Reflect API. Neste post, consideraremos o primeiro.


Proxy


O proxy é uma nova API que permite interceptar, modificar e estender objetos em tempo de execução. Usando esta API, você pode:


  • Logs de perfil e depuração,
  • Interceptar chamadas para propriedades,
  • Valide "em tempo real",
  • etc.

O proxy é um construtor que aceita dois parâmetros: objeto de origem e objeto que atua como um manipulador para o objeto de origem. Este último contém métodos conhecidos como armadilhas.



Um trap é um método que modifica o comportamento de alguma parte do objeto. Por exemplo, a armadilha obtém e define interceptar as chamadas às propriedades para obter e estabelecer um valor, respectivamente, podendo colocar a lógica antes e durante esse processo.


Para entender melhor a utilidade dos proxies, vamos fazer alguns pequenos exercícios.


Exemplo: registro / criação de perfil


Imagine, você tem 17 anos, prestes a completar 18 anos. E você deseja que seu programa o parabenize automaticamente quando você o abrir. Para isso, você pode usar o 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); 

Exemplo: matriz de consulta


Já vimos um exemplo, com as armadilhas get e set mais usadas. Para reforçar, vamos um pouco mais longe e use proxies aninhados. Este exercício tentará converter uma matriz convencional em uma matriz consultável para usar operadores como o SQL groupBy clássico.


Para isso, precisaremos de dois parâmetros de entrada:


  • coleção: matriz de objetos que iremos estender.
  • groupKeys: array de strings que representam as propriedades para as quais você irá agrupar (nome, categoria, preço, 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); 

Conclusões


O Proxy pode não ser o recurso ES6 mais usado, mas junto com a API do Reflect, é um dos mais importantes e interessantes. Sua flexibilidade permite adotá-lo em vários casos e, o melhor de tudo, é fácil de implementar.


Referências


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

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


All Articles