Tutorial

Entendendo as sintaxes de desestruturação, parâmetros rest e espalhamento em JavaScript

Published on June 11, 2020
Português
Entendendo as sintaxes de desestruturação, parâmetros rest e espalhamento em JavaScript

O autor selecionou a COVID-19 Relief Fund​​​​​ para receber uma doação como parte do programa Write for DOnations.

Introdução

Muitas novas funcionalidades para trabalhar com matrizes e objetos foram disponibilizadas para a linguagem JavaScript desde a Edição de 2015 da especificação ECMAScript. Alguns dos elementos notáveis que você aprenderá neste artigo são a desestruturação, os parâmetros rest e a sintaxe de espalhamento. Esses recursos nos dão maneiras mais diretas de acessar os membros de uma matriz ou objeto, e podem tornar o trabalho com essas estruturas de dados mais rápido e sucinto.

Muitas outras linguagens não possuem sintaxes correspondentes para a desestruturação, parâmetros rest e espalhamento. Por este motivo, esses recursos podem ter uma curva de aprendizado tanto para novos desenvolvedores JavaScript quanto para aqueles que estejam vindo de outra linguagem. Neste artigo, você aprenderá como desestruturar objetos e matrizes, como usar o operador de espalhamento para descompactar objetos e matrizes e como usar os parâmetros rest em chamadas de função.

Desestruturação

A atribuição de desestruturação é uma sintaxe que permite que você atribua propriedades de objetos ou itens de matrizes como variáveis. Isso pode reduzir de maneira significativa as linhas de código necessárias para manipular dados nessas estruturas. Existem dois tipos de desestruturação: a desestruturação de objetos e a desestruturação de matrizes.

Desestruturação de objetos

A desestruturação de objetos permite que você crie novas variáveis usando uma propriedade de objeto como o valor.

Considere este exemplo, onde um objeto que representa uma nota com um id, title e date:

const note = {
  id: 1,
  title: 'My first note',
  date: '01/01/1970',
}

Tradicionalmente, se você quisesse criar uma nova variável para cada propriedade, você teria que atribuir cada variável individualmente, com muitas repetições:

// Create variables from the Object properties
const id = note.id
const title = note.title
const date = note.date

Com a desestruturação de objetos, tudo isso pode ser feito em uma linha. Ao colocar cada variável entre chaves {}, o JavaScript criará novas variáveis a partir de cada propriedade com o mesmo nome:

// Destructure properties into variables
const { id, title, date } = note

Agora, use o console.log() nas novas variáveis:

console.log(id)
console.log(title)
console.log(date)

Você receberá os valores originais das propriedades como resultado:

Output
1 My first note 01/01/1970

Nota: a desestruturação de objetos não modifica o objeto original. Você ainda pode chamar a note (nota) original com todas as entradas intactas.

A atribuição padrão para a desestruturação de objetos cria novas variáveis com o mesmo nome que a propriedade do objeto. Se você não quiser que a nova variável tenha o mesmo nome que o nome da propriedade, você também tem a opção de renomear a nova variável usando dois pontos (:) para decidir um novo nome, como visto com o noteId no seguinte exemplo:

// Assign a custom name to a destructured value
const { id: noteId, title, date } = note

Registre a nova variável noteId no console:

console.log(noteId)

Você receberá o seguinte resultado:

Output
1

Você também pode desestruturar valores aninhados de objetos. Por exemplo, atualize o objeto note para que tenha um objeto aninhado author:

const note = {
  id: 1,
  title: 'My first note',
  date: '01/01/1970',
  author: {
    firstName: 'Sherlock',
    lastName: 'Holmes',
  },
}

Agora, você pode desestruturar o note, então desestruturar novamente para criar variáveis a partir das propriedades de author:

// Destructure nested properties
const {
  id,
  title,
  date,
  author: { firstName, lastName },
} = note

Em seguida, registre as novas variáveis firstName e lastName usando os template literals:

console.log(`${firstName} ${lastName}`)

Isso dará o seguinte resultado:

Output
Sherlock Holmes

Observe que neste exemplo, embora você tenha acesso ao conteúdo do objeto author, o objeto author em si não está acessível. Para acessar um objeto, bem como seus valores aninhados, você teria que declará-los separadamente:

// Access object and nested values
const {
  author,
  author: { firstName, lastName },
} = note

console.log(author)

Este código irá gerar o objeto author como resultado:

Output
{firstName: "Sherlock", lastName: "Holmes"}

Desestruturar um objeto é útil não apenas para reduzir a quantidade de código que você precisa escrever, mas também permite que você mire seu acesso nas propriedades que julga importantes.

Por fim, a desestruturação pode ser utilizada para acessar as propriedades de objetos de valores primitivos. Por exemplo, String é um objeto global para strings e possui uma propriedade length (comprimento):

const { length } = 'A string'

Isso encontrará a propriedade de comprimento inerente de uma string e a definirá como sendo igual à variável length. Registre length para ver se o processo funcionou:

console.log(length)

Você receberá o seguinte resultado:

Output
8

Aqui, a string A string foi implicitamente convertida em um objeto para recuperar a propriedade length.

Desestruturação de matrizes

A desestruturação de matrizes permite que você crie novas variáveis usando um item de uma matriz como valor. Considere este exemplo, onde há uma matriz com as várias partes de uma data:

const date = ['1970', '12', '01']

As matrizes em JavaScript garantem a preservação de sua ordem. Dessa forma, neste caso, o primeiro índice será sempre um ano, o segundo será o mês e assim por diante. Sabendo isso, você pode criar variáveis a partir dos itens da matriz:

// Create variables from the Array items
const year = date[0]
const month = date[1]
const day = date[2]

Apesar disso, fazer isso manualmente pode tomar muito espaço do seu código. Com a desestruturação da matriz, você pode descompactar os valores da matriz em ordem e atribuí-los às suas próprias variáveis, desta forma:

// Destructure Array values into variables
const [year, month, day] = date

Agora, registre as novas variáveis:

console.log(year)
console.log(month)
console.log(day)

Você receberá o seguinte resultado:

Output
1970 12 01

Os valores podem ser ignorados deixando a sintaxe de desestruturação em branco entre vírgulas:

// Skip the second item in the array
const [year, , day] = date

console.log(year)
console.log(day)

Ao executar isso, você receberá o valor de year (ano) e day (dia):

Output
1970 01

As matrizes aninhadas também podem ser desestruturadas. Primeiro, crie uma matriz aninhada:

// Create a nested array
const nestedArray = [1, 2, [3, 4], 5]

Em seguida, desestruture aquela matriz e registre as novas variáveis:

// Destructure nested items
const [one, two, [three, four], five] = nestedArray

console.log(one, two, three, four, five)

Você receberá o seguinte resultado:

Output
1 2 3 4 5

A sintaxe de desestruturação pode ser aplicada na desestruturação dos parâmetros em uma função. Para testar isso, você irá desestruturar as keys (chaves) e values (valores) do Object.entries().

Primeiro, declare o objeto de note:

const note = {
  id: 1,
  title: 'My first note',
  date: '01/01/1970',
}

Dado este objeto, você poderia listar os pares de chave de valor através da desestruturação de argumentos à medida em que eles são passados ao método forEach():

// Using forEach
Object.entries(note).forEach(([key, value]) => {
  console.log(`${key}: ${value}`)
})

Ou você poderia alcançar o mesmo resultado usando um loop for:

// Using a for loop
for (let [key, value] of Object.entries(note)) {
  console.log(`${key}: ${value}`)
}

De qualquer maneira, você receberá o seguinte:

Output
id: 1 title: My first note date: 01/01/1970

A desestruturação de objetos e de matrizes podem ser combinadas em uma única atribuição de desestruturação. Os parâmetros padrão também podem ser usados com a desestruturação, como visto no exemplo a seguir que define a data como new Date().

Primeiro, declare o objeto de note:

const note = {
  title: 'My first note',
  author: {
    firstName: 'Sherlock',
    lastName: 'Holmes',
  },
  tags: ['personal', 'writing', 'investigations'],
}

Em seguida, desestruture o objeto, ao mesmo tempo em que você também define uma nova variável date com o padrão de new Date():

const {
  title,
  date = new Date(),
  author: { firstName },
  tags: [personalTag, writingTag],
} = note

console.log(date)

Então, o console.log(date) gerará um resultado semelhante ao seguinte:

Output
Fri May 08 2020 23:53:49 GMT-0500 (Central Daylight Time)

Como mostrado nesta seção, a sintaxe de atribuição de desestruturação adiciona muita flexibilidade ao JavaScript e permite que você escreva códigos mais sucintos. Na próxima seção, você verá como a sintaxe de espalhamento pode ser utilizada para expandir estruturas de dados nas entradas de dados constituintes.

Espalhamento

A sintaxe de espalhamento (...) é outra adição ao JavaScript bastante útil para trabalhar com matrizes, objetos e chamadas de função. O espalhamento permite que objetos e iteráveis (como matrizes) sejam descompactados ou expandidos. Isso pode ser usado para fazer cópias superficiais de estruturas de dados para facilitar a manipulação de dados.

Espalhamento com matrizes

O espalhamento simplifica as tarefas comuns com matrizes. Por exemplo, vamos supor que você tenha duas matrizes e deseja combiná-las:

// Create an Array
const tools = ['hammer', 'screwdriver']
const otherTools = ['wrench', 'saw']

Originalmente, você usaria o concat() para concatenar as duas matrizes:

// Concatenate tools and otherTools together
const allTools = tools.concat(otherTools)

Agora, você também pode usar o espalhamento para descompactar as matrizes em uma nova matriz:

// Unpack the tools Array into the allTools Array
const allTools = [...tools, ...otherTools]

console.log(allTools)

Executar isso resultaria no seguinte:

Output
["hammer", "screwdriver", "wrench", "saw"]

Isso pode ser particularmente útil com a imutabilidade. Por exemplo, você poderia estar trabalhando com um app que possui users (usuários) armazenados em uma matriz de objetos:

// Array of users
const users = [
  { id: 1, name: 'Ben' },
  { id: 2, name: 'Leslie' },
]

Você poderia usar o push para modificar a matriz existente e adicionar um novo usuário, o que seria a opção mutável:

// A new user to be added
const newUser = { id: 3, name: 'Ron' }

users.push(newUser)

Mas isso altera a matriz user, que pode ser que queiramos preservar.

O espalhamento permite que você crie uma nova matriz a partir de uma existente e adicione um novo item no final:

const updatedUsers = [...users, newUser]

console.log(users)
console.log(updatedUsers)

Agora, a nova matriz updatedUsers possui o novo usuário, mas a matriz users original permanece inalterada:

Output
[{id: 1, name: "Ben"} {id: 2, name: "Leslie"}] [{id: 1, name: "Ben"} {id: 2, name: "Leslie"} {id: 3, name: "Ron"}]

Criar cópias de dados em vez de alterar dados existentes ajuda a evitar alterações inesperadas. Em JavaScript, quando você cria um objeto ou matriz e a atribui a outra variável, você não está criando, de fato, um novo objeto — você está passando uma referência.

Observe este exemplo, onde uma matriz é criada e atribuída a outra variável:

// Create an Array
const originalArray = ['one', 'two', 'three']

// Assign Array to another variable
const secondArray = originalArray

Remover o último item da segunda matriz modificará o primeiro:

// Remove the last item of the second Array
secondArray.pop()

console.log(originalArray)

Isso dará o resultado:

Output
["one", "two"]

O espalhamento permite que você crie uma cópia superficial de uma matriz ou objeto. Isso significa que qualquer propriedade de nível superior será clonada, mas objetos aninhados ainda serão passados por referência. Para matrizes ou objetos simples, uma cópia superficial pode ser tudo o que você precisa.

Se você escrever o mesmo código de exemplo, mas copiar a matriz com o espalhamento, a matriz original não será mais modificada:

// Create an Array
const originalArray = ['one', 'two', 'three']

// Use spread to make a shallow copy
const secondArray = [...originalArray]

// Remove the last item of the second Array
secondArray.pop()

console.log(originalArray)

O seguinte ficará registrado no console:

Output
["one", "two", "three"]

O espalhamento também pode ser usado para converter um conjunto, ou qualquer outro iterável em uma matriz.

Crie um novo conjunto e adicione algumas entradas a ele:

// Create a set
const set = new Set()

set.add('octopus')
set.add('starfish')
set.add('whale')

Em seguida, utilize o operador de espalhamento com o set (conjunto) e registre os resultados:

// Convert Set to Array
const seaCreatures = [...set]

console.log(seaCreatures)

Isso resultará no seguinte:

Output
["octopus", "starfish", "whale"]

Isso também pode ser útil para criar uma matriz a partir de uma string:

const string = 'hello'

const stringArray = [...string]

console.log(stringArray)

Isso resultará em uma matriz com cada caractere sendo um item na matriz:

Output
["h", "e", "l", "l", "o"]

Espalhamento com objetos

Ao trabalhar com objetos, o espalhamento pode ser usado para copiar e atualizar objetos.

Originalmente, o Object.assign() era usado para copiar um objeto:

// Create an Object and a copied Object with Object.assign()
const originalObject = { enabled: true, darkMode: false }
const secondObject = Object.assign({}, originalObject)

O secondObject será agora um clone do originalObject.

Isso é simplificado com a sintaxe de espalhamento — você pode copiar um objeto superficialmente, espalhando-o em um novo:

// Create an object and a copied object with spread
const originalObject = { enabled: true, darkMode: false }
const secondObject = { ...originalObject }

console.log(secondObject)

Isso dará como resultado o seguinte:

Output
{enabled: true, darkMode: false}

Assim como com matrizes, isso criará apenas uma cópia superficial e objetos aninhados ainda serão passados por referência.

Adicionar ou modificar propriedades em um objeto existente de maneira imutável torna-se mais simplificado com o espalhamento. Neste exemplo, a propriedade isLoggedIn é adicionada ao objeto user:

const user = {
  id: 3,
  name: 'Ron',
}

const updatedUser = { ...user, isLoggedIn: true }

console.log(updatedUser)

Isso irá mostrar o seguinte:

Output
{id: 3, name: "Ron", isLoggedIn: true}

Uma coisa importante a se notar com a atualização de objetos através do espalhamento é que qualquer objeto aninhado também terá que ser espalhado. Por exemplo, vamos supor que no objeto user existe um objeto organization aninhado:

const user = {
  id: 3,
  name: 'Ron',
  organization: {
    name: 'Parks & Recreation',
    city: 'Pawnee',
  },
}

Se você tentasse adicionar um novo item ao organization, ele substituiria os campos existentes:

const updatedUser = { ...user, organization: { position: 'Director' } }

console.log(updatedUser)

Isso resultaria no seguinte:

Output
id: 3 name: "Ron" organization: {position: "Director"}

Se a mutabilidade não for um problema, o campo poderia ser atualizado diretamente:

user.organization.position = 'Director'

Mas como estamos buscando uma solução imutável, podemos espalhar o objeto interno para reter as propriedades existentes:

const updatedUser = {
  ...user,
  organization: {
    ...user.organization,
    position: 'Director',
  },
}

console.log(updatedUser)

Isso resultará no seguinte:

Output
id: 3 name: "Ron" organization: {name: "Parks & Recreation", city: "Pawnee", position: "Director"}

Espalhamento com chamadas de função

O espalhamento também pode ser usado com argumentos em chamadas de função.

Como um exemplo, aqui está uma função multiply que recebe três parâmetros e os multiplica:

// Create a function to multiply three items
function multiply(a, b, c) {
  return a * b * c
}

Normalmente, você passaria três valores individualmente como argumentos para a chamada de função, desta forma:

multiply(1, 2, 3)

Isso resultaria no seguinte:

Output
6

No entanto, se todos os valores que você deseja passar para a função já existirem em uma matriz, a sintaxe de espalhamento permitirá que você utilize cada item em uma matriz como um argumento:

const numbers = [1, 2, 3]

multiply(...numbers)

Isso gerará o mesmo resultado:

Output
6

Nota: sem o espalhamento, isso pode ser feito usando o apply():

multiply.apply(null, [1, 2, 3])

Isso dará:

Output
6

Agora que você viu como o espalhamento pode encurtar seu código, dê uma olhada em um outro uso da sintaxe ...: os parâmetros rest.

Parâmetros rest

O último recurso que você aprenderá neste artigo é a sintaxe do parâmetro rest. A sintaxe aparece da mesma forma que o espalhamento (...) mas possui o efeito oposto. Ao invés de descompactar uma matriz ou objeto em valores individuais, a sintaxe do rest criará uma matriz de um número de argumentos indefinido.

Na função restTest por exemplo, se quiséssemos que o args fosse uma matriz composta por um número de argumentos indefinido, poderíamos ter o seguinte:

function restTest(...args) {
  console.log(args)
}

restTest(1, 2, 3, 4, 5, 6)

Todos os argumentos passados para a função restTest estão agora disponíveis na matriz args:

Output
[1, 2, 3, 4, 5, 6]

A sintaxe rest pode ser usada como o único parâmetro ou como o último parâmetro na lista. Se usada como único parâmetro, ela reunirá todos os argumentos. No entanto, se for usada no final de uma lista, ela reunirá todos os argumentos remanescentes, como visto neste exemplo:

function restTest(one, two, ...args) {
  console.log(one)
  console.log(two)
  console.log(args)
}

restTest(1, 2, 3, 4, 5, 6)

Isso pegará os dois primeiros argumentos individualmente. Em seguida, agrupará o restante em uma matriz:

Output
1 2 [3, 4, 5, 6]

Em código mais antigo, a variável arguments poderia ser usada para reunir todos os argumentos passados para uma função:

function testArguments() {
  console.log(arguments)
}

testArguments('how', 'many', 'arguments')

O resultaria no seguinte:

[secondary_label Output]1
Arguments(3) ["how", "many", "arguments"]

No entanto, isso possui algumas desvantagens. Primeiro, a variável arguments não pode ser usada com funções de flecha.

const testArguments = () => {
  console.log(arguments)
}

testArguments('how', 'many', 'arguments')

Isso geraria um erro:

Output
Uncaught ReferenceError: arguments is not defined

Além disso, arguments não é uma matriz verdadeira e não pode usar métodos como map e filter sem que seja primeiro convertida em uma matriz. Ela também irá coletar todos os argumentos passados em vez de apenas o restante dos argumentos, como visto no exemplo restTest(one, two, ...args).

Os parâmetros rest também podem ser usados na desestruturação de matrizes:

const [firstTool, ...rest] = ['hammer', 'screwdriver', 'wrench']

console.log(firstTool)
console.log(rest)

Isso dará:

Output
hammer ["screwdriver", "wrench"]

Os parâmetros rest também podem ser usados na desestruturação de objetos:

const { isLoggedIn, ...rest } = { id: 1, name: 'Ben', isLoggedIn: true }

console.log(isLoggedIn)
console.log(rest)

Gerando o seguinte resultado:

Output
true {id: 1, name: "Ben"}

Desta forma, a sintaxe rest fornece métodos eficientes para reunir uma quantidade indeterminada de itens.

Conclusão

Neste artigo, você aprendeu sobre desestruturação, sintaxe de espalhamento e parâmetros rest. Resumindo:

  • A desestruturação é utilizada para criar variáveis a partir dos itens de matrizes ou propriedades de objetos.
  • A sintaxe de espalhamento é usada para descompactar iteráveis como matrizes, objetos e chamadas de função.
  • A sintaxe do parâmetro rest criará uma matriz a partir de um número indefinido de valores.

As sintaxes de desestruturação, parâmetros rest e espalhamento são recursos úteis no JavaScript que ajudam a manter seu código sucinto e limpo.

Se você quiser ver a desestruturação em ação, dê uma olhada em Como personalizar componentes React com o Props, que utiliza essa sintaxe para desestruturar dados e passá-los para componentes personalizados de front-end. Se você quiser aprender mais sobre o JavaScript, retorne para nossa página da série Como programar em JavaScript.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors

Default avatar

Senior Technical Editor

Editor at DigitalOcean, fiction writer and podcaster elsewhere, always searching for the next good nautical pun!


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel