Operadores Spread vs Rest em JavaScript
Tags: spread, rest, javascript, beginners
Published: 2024-03-12 12:33:57

Conteúdo:

  * [Definição] (#definition)
  * [Operador Spread] (#spread-op)
    * [Concatenando Arrays] (#concatenating)
    * [Unindo Objetos] (#merging-objects)
    * [Copiando Arrays e Objetos] (#copying)
    * [Transformando Strings em Arrays] (#strings-into-arrays)
  * [Operador Rest] (#rest-op)
    * [Parâmetros de Função] (#function-parameters)
  * [Desestruturação com Rest e Spread] (#destructuring)

Vem aprender a usar os três pontinhos no seu código. Depois desse artigo você não vai mais esquecer a diferença entre eles! 🐱🐱🐱

### Definição <a name="definition"></a>:

  * O **spread** é o operador quer nos permite **expandir iteráveis** em elementos individuais.

  * O **rest** é o operador que usamos para representar um **número indefinido** de argumentos em um **array**.

Ambos são escritos utilizando os três pontos `...`, mas você verá que é fácil identificar quando é um spread e quando é um rest! No final tem também uma dica boa para você!


### Operador Spread <a name="spread-op"></a>

#### Concatenando Arrays <a name="concatenating"></a>

O spread permite que unamos dois ou mais arrays, mantendo uma linguagem concisa e limpa. 

Vamos tomar um café? ☕️ Considere os dois arrays abaixo:

```javascript
const coffee = ['café', 'água'];
const spices = ['canela', 'noz-moscada', 'cardamomo'];
```

Para temperar o café, precisamos misturar os arrays `coffee` e `spices`. Podemos usar o spread para juntá-los em um único array:

```javascript
const coffeeReady = [...coffee, ...spices];

console.log(coffeeReady) 
// output:
// ['café', 'água', 'canela', 'noz-moscada', 'cardamomo'];
```
Simples, não? Muito melhor do que escrever item por item de cada um dos dois arrays para formar `coffeeReady`. 

**Importante**: 

**1. Alterações em `coffee` não afetarão `coffeeReady`!**

Para entender melhor: quando fazemos uma cópia, podemos criar uma **nova referência** ao valor original ou apenas copiar o **valor**. Criar uma nova referência nada mais é do que criar uma variável que apontará para o **local na memória em que está o valor original**. 

Caso tivéssemos criado uma nova referência, qualquer alteração em `coffee` alteraria `coffeeReady` e vice-e-versa, pois ambos apontariam para o dado armazenado no mesmo local. Mas o que fizemos com o spread foi copiar apenas o valor, que por sua vez ficará armazenado em **outro local da memória**. Assim, alterações em um array não afetarão o outro. 

No entanto, alguns detalhes poderiam mudar esse quadro! Isso porque...

**2. O spread apenas cria uma cópia superficial (shallow copy)!**

Isso significa que, dependendo dos dados contidos em `coffee`, algumas alterações poderiam sim alterar `coffeeReady`! Se `coffee` contivesse algum valor **não-primitivo**, o computador teria criado uma referência para os valores na memória. Assim, qualquer alteração em um array, afetaria o outro, em relação aos dados não-primitivos, já que ambos estariam armazenando uma referência para o mesmo local da memória. Veja abaixo:

```javascript
let a = [1, [2, 3]];
const b = [4, 5, 6];
// [2, 3] é um array aninhado em a, e portanto
// é um valor não-primitivo

let c = [...a, ...b];
console.log(c);
// output: [1, [2, 3], 4, 5, 6]

a[0] = 11;
a[1][0] = 22;

console.log(c);
// output: [1, [22, 3], 4, 5, 6]
```
 
Veja acima que alterar `a[0]` não afetou `c`, pois alteramos um valor primitivo, ou seja `a[0]` e `c` apontam para valores iguais, mas que estão em **locais diferentes na memória**. No entanto, alterar `a[1][0]`, modificou `c`, porque alteramos um array, que é um valor não-primtivo. Assim, alteramos um valor contido no espaço de memória, para o qual tanto `a[1][0]` quanto `c` apontam.

#### Unindo Objetos <a name="merging-objects"></a>

Também podemos unir objetos em um só usando o spread:

```javascript
const myParents = { 
  fathersName: 'Michael', 
  mothersName: 'Louise'
};
const mySiblings = { 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
};

const myFamily = { ...myParents, ...mySiblings };
console.log(myFamily);
/* output:
{ 
  fathersName: 'Michael', 
  mothersName: 'Louise', 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
} 
*/
```
No entanto, é importante lembrar que **o spread não clona propriedades idênticas!** Abaixo temos dois objetos com `brothersName`:

```javascript
const myParents = { 
  fathersName: 'Michael', 
  mothersName: 'Louise',
  brothersName: 'Gabriel'
};
const mySiblings = { 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
};

const myFamily = { ...myParents, ...mySiblings };
console.log(myFamily);
// output:
/* { 
  fathersName: 'Michael', 
  mothersName: 'Louise', 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
}
```
Veja que o objeto final não herda as duas chaves `brothersName`. Na verdade, apenas uma prevalece, que é a do **segundo objeto**.

#### Copiando Arrays e Objetos<a name="copying"></a>

Pegou a ideia até agora? Se podemos unir arrays e também objetos, isso significa também que podemos copiá-los individualmente:

```javascript
// criando uma cópia superficial de coffee:
const coffee = ['café', 'água'];
const coffeeCopy = [...coffee];
console.log(coffeeCopy)
// output: 
// ['café', 'água'];

// criando uma cópia superficial de mySiblings:
const mySiblings = { 
  brothersName: 'Philip', 
  sistersName: 'Lara' 
};

const myFamily = { 
  fathersName: 'Michael', 
  mothersName: 'Louise',
  ...mySiblings
};
// e agora podemos tratar brothersName e sistersName como
// uma propriedade de myFamily:
console.log(myFamily.brothersName) 
// output: Philip
```

#### Transformando Strings em Arrays <a name="strings-into-arrays"></a>

É também possível usar o spread para transformar uma string em um array. Isso nos permite ter mais flexibilidade ao manipular strings, pois dessa maneira conseguimos aplicar métodos de arrays em strings:

```javascript
const str = 'coffee';
const letters = [...str, 's.', '☕️']; 
console.log(letters);// ["c", "o", "f", "f", "e", "e", "s.", ☕️"]
```

### Operador Rest <a name="rest-op"></a>

Conforme dito acima, o operador rest é usado para empacotar elementos em um array. Você verá que o rest é um grande aliado para quando lidamos com muitos valores ou número de valores incertos. 

#### Parâmetros de Função <a name="function-parameters"></a>

O operador rest permite representar um número indefinido de argumentos como um array.

```javascript
const order = function(beverage, ...otherIngredients) {
  console.log(beverage);
  console.log(otherIngredients);
};

order('chá verde', 'leite', 'açúcar mascavo'); 
// output:
// chá verde 
// ['leite', 'açúcar mascavo']
```

Veja que isso nos permite chamar a mesma função com mais argumentos, pois o rest os colocará todos no array `otherIngredients`:

```javascript
const order = function(beverage, ...otherIngredients) {
  console.log(beverage);
  console.log(otherIngredients);
};

order('chá verde', 'leite', 'açúcar mascavo', 'hortelã', 'cumaru'); 
// output:
// chá verde 
// ['leite', 'açúcar mascavo', 'hortelã', 'cumaru']
```

🍵 Um detalhe importante é que o rest deve ser o **último parâmetro** na função! Se escrevêssemos `function(...otherIngredients, beverage)` o computador não saberia quando parar e isso geraria um erro.


### Desestruturação com Rest e Spread <a name="destructuring"></a>

O rest e o spread também são muito utilizados em desestruturação. Se você não sabe ainda o que é isso, sugiro meus outros dois artigos aqui: [desestruturação de arrays](https://dev.to/barobles/desestruturacao-de-arrays-em-javascript-3if5) e [desestruturação de objetos](https://dev.to/barobles/desestruturando-objetos-em-javascript-object-destructuring-4gmb).

Usando rest:

```javascript
const [a, b, ...others] = [1, 2, 3, 4, 5];
console.log(a, b, others); 
// output: 1 2 [3, 4, 5]
```

Usando spread:

```javascript
const array = [1, 2, ...[3, 4, 5]];
console.log(array); 
// output: [1, 2, 3, 4, 5]
```

Agora, pega essa dica para você não confundir rest com o spread aqui: o rest fica do lado **esquerdo** de `=` e o spread fica do lado **direito** de `=`.

...rest = ☕️

🍵 = ...spread

Obrigada por chegar até aqui! Espero que esse post tenha te ajudado! Comenta o que achou!