Menu

Operador Spread e Rest em JavaScript: o que faz o ...

Entenda como o operador ... funciona em JavaScript: use rest para juntar argumentos em um array e spread para expandir arrays e objetos. Veja quando usar cada um.

Mesma sintaxe, duas funções

As três reticências ... aparecem bastante no JavaScript moderno, e fazem coisas opostas dependendo de onde estão escritas. Depois que você pega o padrão, todo uso de ... cai em um de dois baldes:

  • Rest: ...nome do lado que recebe junta vários valores em um único array ou objeto.
  • Spread: ...valor do lado que entrega expande um array ou objeto nas suas partes individuais.

Esse é o modelo mental completo. O resto desta página são só exemplos de cada um e os padrões que você vai usar toda hora.

Rest parameters: juntando argumentos

Um rest parameter na definição de uma função junta qualquer quantidade de argumentos em um array de verdade:

index.js
Output
Click Run to see the output here.

nums é um array comum. Dá pra fazer .map, .filter, checar o .length, passar pra outra função — tudo que array faz.

Dá pra misturar rest parameters com parâmetros normais, mas o rest parameter precisa vir sempre por último:

index.js
Output
Click Run to see the output here.

label engole o primeiro argumento; tudo que vier depois cai em items. Colocar o rest parameter em qualquer posição que não seja a última gera erro de sintaxe.

Rest vs. o antigo objeto arguments

Códigos JavaScript mais antigos usam uma variável mágica chamada arguments dentro de funções normais. Ela parece um array, mas não é — então os métodos de array não funcionam direto nela. Os rest parameters resolvem isso de forma muito mais limpa:

index.js
Output
Click Run to see the output here.

As arrow functions nem possuem o objeto arguments, então os rest parameters são a única forma de receber um número variável de argumentos nelas. Em código novo, prefira sempre ...args.

Spread em chamadas de função

O spread faz o caminho inverso: pega um array e o "desempacota" em argumentos individuais na hora da chamada.

index.js
Output
Click Run to see the output here.

Math.max aceita números individuais, não um array. Antes do spread, a gente precisava escrever Math.max.apply(null, nums). Agora é só um ... e pronto.

Repare que o mesmo ... vira rest na definição da função e spread na chamada da função — a posição é que determina qual dos dois é.

Spread em arrays literais

Usar spread dentro de um array literal serve para copiar ou combinar arrays:

index.js
Output
Click Run to see the output here.

[...a] devolve um array novo com os mesmos elementos — perfeito quando você quer ordenar ou modificar sem mexer no original:

index.js
Output
Click Run to see the output here.

scores continua intacto porque o .sort rodou em cima da cópia. É um hábito simples, mas que faz toda a diferença quando você escreve código que não pode ter efeitos colaterais inesperados.

Spread em objetos no JavaScript

O operador spread também funciona com objetos comuns, juntando as propriedades de cada um em um novo objeto:

index.js
Output
Click Run to see the output here.

As chaves que vêm depois vencem. O updates.age sobrescreve o user.age, e o city entra junto de carona. A ordem dos spreads define o resultado — fica de olho nisso quando estiver empilhando valores padrão e sobrescritas:

index.js
Output
Click Run to see the output here.

Defaults primeiro, escolhas do usuário depois. O fontSize definido pelo usuário prevalece, e o theme é herdado.

A armadilha da cópia rasa

O spread copia apenas um nível de profundidade. Objetos e arrays aninhados continuam compartilhados entre o original e a cópia:

index.js
Output
Click Run to see the output here.

Os dois arrays mostram a nova tag porque copy.tags e original.tags são, na prática, o mesmo array. O spread não clonou a lista aninhada — apenas copiou a referência.

Quando você realmente precisa de uma cópia profunda de dados simples, use structuredClone:

index.js
Output
Click Run to see the output here.

Agora os dois arrays são independentes. O structuredClone já vem nativo nos navegadores modernos e no Node, dá conta de estruturas aninhadas e é a escolha certa sempre que uma cópia rasa não resolve.

Rest na desestruturação

O rest também funciona na desestruturação, juntando os elementos ou propriedades que sobraram:

index.js
Output
Click Run to see the output here.

Separar alguns campos e manter o restante em um único objeto é um padrão bem comum quando você precisa repassar props, remover campos sensíveis ou montar versões modificadas de um dado:

index.js
Output
Click Run to see the output here.

password é extraído (e ignorado), enquanto safe fica com todo o resto. Sem mutação e sem ter que copiar na mão.

Recapitulando rapidinho

  • ...nome numa lista de parâmetros ou num padrão de desestruturação é rest: ele coleta.
  • ...valor numa chamada de função, array literal ou objeto literal é spread: ele expande.
  • As cópias feitas com spread são rasas. Estruturas aninhadas continuam compartilhadas. Para cópia profunda, use structuredClone.
  • Rest parameters são arrays de verdade — prefira eles em vez de arguments.
  • Em objetos literais, os spreads posteriores sobrescrevem os anteriores, e é assim que se monta aquele esquema de valores padrão com overrides.

A seguir: Closures

Funções em JavaScript não apenas recebem entradas e devolvem saídas — elas também lembram do escopo em que foram definidas. Esse "memória" é o que chamamos de closure, e é o mecanismo por trás de callbacks, factories e da maioria dos padrões que você vai encontrar na próxima página.

Perguntas frequentes

Qual a diferença entre rest e spread em JavaScript?

A sintaxe é a mesma (...), mas o papel é oposto. O rest junta vários valores em um único array — aparece na lista de parâmetros de funções e em destructuring. Já o spread expande um iterável ou objeto nos seus elementos — aparece em chamadas de função, literais de array e literais de objeto. Regra prática: se o ... está no lado que recebe, é rest; se está no lado que entrega, é spread.

Como funcionam os rest parameters em uma função?

Um rest parameter como function sum(...nums) agrupa todos os argumentos passados para a função em um array de verdade chamado nums. Ele precisa ser sempre o último parâmetro da lista. Diferente do velho objeto arguments, o rest parameter é um array real, então você pode chamar .map, .filter e .reduce direto nele, sem gambiarra.

O spread faz uma cópia profunda (deep copy) do objeto?

Não. O spread copia apenas um nível — é uma shallow copy. { ...user } gera um novo objeto com as mesmas chaves do topo, mas objetos e arrays aninhados continuam apontando para a mesma referência. Se precisar de cópia profunda, use structuredClone(value) ou, para dados simples, passe pelo JSON.parse(JSON.stringify(...)).

Aprenda a programar com o Coddy

COMEÇAR