Pressione enter para ver os resultados ou esc para cancelar.

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:

http://babeljs.io/repl/

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 (;