Operadores Spread vs Rest em JavaScript

barobles

Barbara Robles 🇧🇷

Posted on March 12, 2024

Operadores Spread vs Rest em JavaScript

Conteúdo:

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 :

  • 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

Concatenando Arrays

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

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

const coffee = ['café', 'água'];
const spices = ['canela', 'noz-moscada', 'cardamomo'];
Enter fullscreen mode Exit fullscreen mode

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

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

console.log(coffeeReady) 
// output:
// ['café', 'água', 'canela', 'noz-moscada', 'cardamomo'];
Enter fullscreen mode Exit fullscreen mode

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:

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]
Enter fullscreen mode Exit fullscreen mode

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

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

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' 
} 
*/
Enter fullscreen mode Exit fullscreen mode

No entanto, é importante lembrar que o spread não clona propriedades idênticas! Abaixo temos dois objetos com brothersName:

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' 
}
Enter fullscreen mode Exit fullscreen mode

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

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

// 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
Enter fullscreen mode Exit fullscreen mode

Transformando Strings em Arrays

É 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:

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

Operador Rest

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

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

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']
Enter fullscreen mode Exit fullscreen mode

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

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']
Enter fullscreen mode Exit fullscreen mode

🍵 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

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 e desestruturação de objetos.

Usando rest:

const [a, b, ...others] = [1, 2, 3, 4, 5];
console.log(a, b, others); 
// output: 1 2 [3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Usando spread:

const array = [1, 2, ...[3, 4, 5]];
console.log(array); 
// output: [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

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!

💖 💪 🙅 🚩
barobles
Barbara Robles 🇧🇷

Posted on March 12, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related