Desestruturação de objetos e arrays no Javascript (destructuring)
A atribuição via desestruturação é uma prática muito comum no desenvolvimento de aplicações modernas com Javascript. Foi introduzido na especificação Ecmascript 6 e trouxe bastante flexibilidade e legibilidade na utilização de arrays e objetos no Javascript.
Consiste basicamente em extrair elementos de dentro de arrays e objetos, de modo a garantir bastante legibilidade e evitar o uso extremo de notação de pontos muito profundas. Veja como geralmente era feito, considerando o objeto abaixo:
var ficha = {
nome: 'gughog',
level: 10,
emblemas: ['Fogo', 'Gelo'],
itens: {
cabeca: ['Helmo de aço'],
torso: ['Manoplas de aço'],
bracos: ['Calças de aço'],
pernas: ['Botas de aço', 'Botas de couro +2', 'Botas reluzentes'],
},
skills: {
magia: {
fogo: 'Bola de fogo +9',
gelo: 'Tempestade gélida +7',
eletrico: null,
terra: null
}
}
}
Temos aqui um objeto com diversos níveis de dados. Caso precisemos logar o valor do level da ficha, fazemos algo assim:
console.log(ficha.level)
Caso precisemos acessar um valor mais profundo, como o valor da skill de fogo, fariamos assim:
console.log(ficha.skills.magia.fogo)
Em pequenos objetos/arrays talvez não tenham muitos problemas usar dessa notação de ponto para acessar, caso esses elementos não possuam subelementos muto profundos, mas isso acaba tornando o desenvolvimento cansativo,* verboso, *chato e repetitivo. Isso é tudo que nós desenvolvedores devemos evitar, e é com esses preceitos que o destructuring chegou.
Desestruturando poderiamos simplesmente acessar esses mesmos elementos dessa forma:
console.log(level)
console.log(fogo)
Obviamente poderiamos fazer isso para alcançar o mesmo efeito:
var level = ficha.level
var fogo = ficha.skills.magia.fogo
Mas aí estariamos atribuindo a uma nova variável um valor que já existia, e isso não chega nem perto da elegância e da engenhosidade do destructuring.
Desestruturando objetos
Ainda utilizando-se do nosso objeto ficha, vamos apenas atualizá-lo para o ECMAScript 6, removendo essa horrenda var
para usar algo mais moderno:
const ficha = {
nome: 'gughog',
level: 10,
emblemas: ['Fogo', 'Gelo'],
itens: {
cabeca: ['Helmo de aço'],
torso: ['Manoplas de aço'],
bracos: ['Calças de aço'],
pernas: ['Botas de aço', 'Botas de couro +2', 'Botas reluzentes'],
},
skills: {
magia: {
fogo: 'Bola de fogo +9',
gelo: 'Tempestade gélida +7',
eletrico: null,
terra: null
}
}
}
Então, via desestruturação, vamos acessar as mesmas variáveis:
const { level } = ficha
console.log(level) // 10
Mas o que diabos aconteceu aqui?!
Utilizando-se das chaves, declaramos nela as variáveis que queremos extrair de um objeto que foi apontado depois do sinal de igual. No geral, podemos ler essa expressão assim:
"Extraio o parametro
level
do objetoficha
. "
Desestruturando parametros objetos com um nome novo
Caso quisermos extrair level
e dar um nome diferente, podemos fazer assim:
const { level: nivelDoPersonagem } = ficha
console.log(nivelDoPersonagem)
Desestruturando parametros de objetos em níveis profundos
No exemplo temos o valor da magia de fogo. Como podemos fazer para acessar esse parametro, já que o mesmo possui mais de um nível de profundidade? Temos duas formas:
-
Maneira preguiçosa:
// extraimos o parametro do caminho que fizemos com a notaçãode pontos const { fogo } = ficha.skills.magia console.log(fogo)
-
Maneira mais criativa:
// acessamos nível por nível de um objeto especificado const { skills: { magia: {fogo} } } = ficha console.log(fogo)
Desestruturando arrays
Também podemos desestruturar arrays e extrair apenas os elementos dos indexes que desejarmos, de modo a evitar acessar elementos via index. Veja como fariamos da maneira antiga:
console.log(ficha.emblemas[0])
No exemplo, acessamos o primeiro item da array de emblemas do nosso personagem.
O destructuring nas arrays funciona de forma muito parecida, com algumas pequenas peculiaridades. Vamos agora desestruturar para acessar o mesmo elemento, via destructuring:
const [ emblemaFogo ] = ficha.emblemas
console.log(emblemaFogo) // Fogo
Para acessar um outro elemento que não o primeiro, podemos simplemente omitir e ir passando adicionando vírgulas:
// aqui omitimos o primeiro item e acessamos o segundo:
const [ , emblemaGelo ] = ficha.emblemas
console.log(emblemaGelo) // Gelo
O nome que usamos dentro da array desestruturada pode ser qualquer um que você queira, funciona como uma variável, então, use sua criatividade.
Desestruturação de elementos profundos de arrays
Para desestruturar arrays contidas em arrays, podemos fazer o seguinte, mas primeiro considere essa array:
const chefes = [
[ 'Dragão Menor', 'Ciclope Verde', 'Largato Selvagem' ],
[ 'Reaper', 'Cavaleiro Sombrio', 'Minotauro Vermelho' ]
]
Para desestruturar apenas o primeiro valor da primeira array, fazemos algo assim:
const [[dragaoMenor]] = chefes;
console.log(dragaoMenor)
Se tivessemos níveis ainda mais profundos:
const chefes = [
[ [['Aranha', 'Besouro']], 'Dragão Menor', 'Ciclope Verde', 'Largato Selvagem' ],
[ 'Reaper', 'Cavaleiro Sombrio', 'Minotauro Vermelho' ]
]
const [[[[aranha]]]] = chefes;
console.log(aranha) // Aranha
Desestruturação de parametros de funções
É muito comum passarmos parametros para nossas funções e agruparmos todos estes em um objeto só. Considere a função a seguir:
function atacarInimigo (props) {
// se nenhum inimigo for especificado, a função termina aqui
if (props.inimigo === null) {
console.log('Você tentou atacar alguém... mas não tinha ninguém!')
return
}
// usando template strings
console.log(
`Você atacou ${props.inimigo} e proferiu ${props.dano} pontos de dano! `
)
}
// os parametros da função
const parametros = { inimigo: 'Aranha', dano: 32 }
atacarInimigo(parametros) // Você atacou Aranha e proferiu 32 pontos de dano!
Perceba que acabamos tendo que acessar os parametros via notação de ponto por diversas vezes. Podemos deixar muito mais limpo fazendo o destructuring dos parametros da função. Veja a funçaõ refatorada:
function atacarInimigo (props) {
const { inimigo, dano } = props
if (inimigo === null) {
console.log('Você tentou atacar alguém... mas não tinha ninguém!')
return
}
// usando template strings
console.log(
`Você atacou ${inimigo} e proferiu ${dano} pontos de dano! `
)
}
const parametros = { inimigo: 'Aranha', dano: 32 }
atacarInimigo(parametros)
Leia um pouco sobre template string no nosso post: Concatenando Strings no Javascript
Perceba que agora temos muito menos níveis acessados com a notação de pontos, temos apenas as variáveis em si referenciadas.
Considerações finais
O destructuring é um assunto bastante rico, definitivamente é um tema essencial de se dominar para quem desenvolve aplicações modernas com Javascript, principalmente utilizando React. Espero que o assunto esteja um pouco mais claro agora e até o próximo post!