Desmitificando o destructuring do JavaScript ES6/ES7
As novas especificações do EcmaScript trouxeram uma série de melhorias e recursos adicionais na sintaxe e funcionalidade da linguagem. Uma delas que particularmente gosto e uso bastante, por ajudar a deixar o código mais curto e mais claro, é a possibilidade de fazer destructuring em objetos e arrays.
Entender o que esse recurso faz é simples: ele facilita o acesso a dados dentro de um array ou objeto e a criação de variáveis que contenham esses dados. Porém isso não quer dizer que ele faça pouca coisa. Na verdade, suas aplicações são bastante diversas, e vou tentar contemplar algumas neste post.
Declaração de variáveis
Imaginemos declarar variáveis para dados dentro do seguinte objeto:
company = { name: ‘ACME Corp’, address: ‘Nowhere st’, products: { shirts: { colors: [‘red’, ‘green’, ‘blue’] }, socks: { colors: [‘cyan’, ‘magenta’, ‘yellow’] } } };
Vamos mostrar no console o nome da empresa e as cores de camisetas usando ES5:
var companyName = company.name; var shirtsColors = company.products.shirts.colors; console.log(companyName); // 'ACME Corp' console.log(shirtsColors); // [‘red’, ‘green’, ‘blue’]
Agora vamos ver como ficaria usando ES6:
const { name, products: { shirts: { colors } } } = company console.log(name); // 'ACME Corp' console.log(colors); // [‘red’, ‘green’, ‘blue’]
É interessante ver como não é mais necessário escrever múltiplas declarações de variáveis de um mesmo objeto. A nova sintaxe facilita a extração dos dados.
Mas e se eu quiser que o nome da variável seja diferente do nome da propriedade do objeto?
É possível extrair o dado do objeto renomeando a variável que está sendo declarada:
const { name: companyName, products: { shirts: { colors: shirtsColors } } } = company console.log(companyName) // 'ACME Corp' console.log(shirtsColors) // [‘red’, ‘green’, ‘blue’]
E como evito valores não definidos?
Caso alguma propriedade dentro do objeto em questão possa, em certas ocasiões, não estar declarada, é possível tratar isso atribuindo a ela um valor padrão:
const { products: { shirts: { sizes: shirtsSizes = [] } } } = company console.log(shirtsSizes) // []
Destructuring de objetos que são argumentos em uma função
Quando uma função recebe um objeto como argumento, é comum que precisemos usar atributos dentro desse objeto para executar comandos dentro da função.
Exemplo usando ES5:
var getShirtsColorsAmount = function (company) { colors = company.products.shirts.colors; return colors.length; } getShirtsColorsAmount(company); // 3
Exemplo usando ES6:
const getShirtsColorsAmount = ({ products: { shirts: { colors: { length } } } }) => length getShirtsColorsAmount(company) // 3
Renomear e atribuir valor padrão continua valendo:
const getShirtsSizes = ({ products: { shirts: { sizes: shirtsSizes = [] } } }) => shirtsSizes getShirtsSizes(company) // []
Spread operator, aquele dos três pontinhos
Imaginemos o seguinte objeto:
const clothes = { pants: { colors: [‘black’, ‘blue’] }, shirts: { colors: [‘white’, ‘red’] }, socks: { colors: [‘beige’, ‘gray’] }, }
Digamos que eu queira consumir apenas os dados de roupas que não são calças. Não existe nenhum jeito nativo de fazer isso na especificação antiga. A solução dependeria do caso de uso e poderia ser necessário usar um loop. Porém, com o spread operator isso fica muito fácil:
const { pants, ...rest } = clothes console.log(rest) // { // shirts: { colors: [‘white’, ‘red’] }, // socks: { colors: [‘beige’, ‘gray’] }, // }
Plus a mais: além de auxiliar com o destructuring, o spread operator é útil para clonar e concatenar objetos.
const otherClothes = { ...clothes } console.log(otherClothes) // { // pants: { colors: [‘black’, ‘blue’] }, // shirts: { colors: [‘white’, ‘red’] }, // socks: { colors: [‘beige’, ‘gray’] }, // } const moreClothes = { ...clothes, shoes: { colors: [‘yellow’, ‘purple’] }, } console.log(moreClothes) // { // pants: { colors: [‘black’, ‘blue’] }, // shirts: { colors: [‘white’, ‘red’] }, // socks: { colors: [‘beige’, ‘gray’] }, // shoes: { colors: [‘yellow’, ‘purple’] }, // }
Destructuring de arrays
Além de objetos, também podemos fazer isso com arrays:
const myArr = [1, 2, 3] const [a, b, c] = myArr console.log(b) // 2
Valores default continuam valendo:
const [a, b, c, d = 4] = myArr console.log(d) // 4
E o spread operator também funciona:
const arr = [1, 2, 3] const arr2 = [4, 5, 6] console.log([...arr, ...arr2]) // [1, 2, 3, 4, 5, 6] const [a, ...rest] = arr console.log(rest) // [2, 3]
Se você quer experimentar um pouco mais este e outros recursos, o Babel, que é um transpilador de JS (serve para escrevermos código com as especificações novas para plataformas onde elas ainda não são totalmente suportadas) possui uma ferramenta em seu site para isso:
Conclusão
O destructuring possui mais recursos e aplicações mais avançadas, mas com este conteúdo já se tem o necessário para começar a usá-lo e simplificar seu código. Como vimos nos exemplos, ele é bastante útil para facilitar a leitura do código e o acesso a valores que precisamos em determinado contexto. Com pouco esforço, temos a variável que queremos, no lugar que queremos, com o nome e valor que queremos e até tratando valores nulos ou indefinidos.
Qualquer dúvida ou consideração sobre o artigo, por favor deixe nos comentários. Até a próxima (;