JavaScript Rest e Spread Syntax
Conheça os parâmetros rest e o spread syntax do JavaScript: como coletar argumentos variáveis e expandir iteráveis de forma concisa e eficiente.
Em JavaScript, o token de três pontos ... executa dois trabalhos opostos dependendo de onde é escrito. Como parâmetro de função, ele coleta vários argumentos em um único array — isso é um parâmetro rest. Em qualquer outro lugar, ele expande um iterável ou object em suas partes individuais — isso é o spread syntax. Mesmo símbolo, significado espelhado.
Ambos foram introduzidos no ES6 (2015). Esta página aborda os parâmetros rest (incluindo a regra de que devem vir por último), spread em chamadas de função, literais de array e literais de object, como copiar e mesclar com spread, como rest difere de spread e por que ambos superam o antigo objeto arguments.
Entendendo os Parâmetros Rest em JavaScript
Um parâmetro rest permite que uma função aceite um número indefinido de argumentos e os receba como um array de verdade. Você escreve ... seguido de um nome; esse nome torna-se um array que contém todos os argumentos que não foram capturados por um parâmetro anterior.
Sintaxe e Uso
No exemplo abaixo, numbers é um array comum, então você pode chamar métodos de array como reduce diretamente nele — sem conversão necessária.
O Parâmetro Rest Deve Ser o Último
Uma função pode ter apenas um parâmetro rest, e ele deve ser o último na lista de parâmetros. Os parâmetros nomeados antes dele são preenchidos primeiro; o parâmetro rest então captura tudo o que restar. Colocá-lo em qualquer outra posição resulta em um SyntaxError.
Vantagens sobre o Objeto arguments
Antes do ES6, a única maneira de ler todos os argumentos era por meio do objeto especial arguments, disponível dentro de funções não-arrow. Os parâmetros rest são melhores em quase todos os aspectos:
- Um array de verdade.
argumentsé semelhante a um array (temlengthe índices), mas não possuimap,filter,reduce, etc. Um parâmetro rest é um array genuíno. - Explícito e legível. A assinatura
function sum(...numbers)informa ao leitor que a função aceita uma lista variável.argumentsé invisível na assinatura. - Você pode nomear apenas os extras. Combine parâmetros fixos com um parâmetro rest, como mostrado acima —
argumentssempre contém todos os argumentos, incluindo os que você já nomeou. - Funciona com arrow functions. Arrow functions não possuem seu próprio objeto
arguments, portanto, um parâmetro rest é a única forma de reunir argumentos variáveis em uma arrow function.
Mergulhando no Spread Syntax
O spread syntax expande um iterável — um array, string, Set, Map ou qualquer iterável — em seus elementos individuais onde quer que uma lista de valores seja esperada. Os três contextos em que você o usará são chamadas de função, literais de array e literais de object.
Spread em Literais de Array
Dentro de [ ], o spread insere cada elemento de um iterável no novo array. Esta é a forma mais limpa de inserir um array dentro de outro em qualquer posição:
Como strings são iteráveis, fazer spread de uma produz um array com seus caracteres:
Spread em Chamadas de Função
Em uma chamada de função, o spread transforma um array de volta em uma lista de argumentos separados. Isso substitui o antigo padrão func.apply(null, array):
Spread em Literais de Object
Dentro de { }, o spread copia as propriedades próprias enumeráveis de um object em um novo object. Quando as chaves colidem, o valor posterior vence — o que torna o spread perfeito para aplicar substituições ou valores padrão:
Copiando e Mesclando
O spread é a forma idiomática de fazer uma cópia superficial ou mesclar coleções sem mutar os originais:
O spread é superficial. Ele copia apenas os valores do nível superior. Objects e arrays aninhados ainda são compartilhados por referência, portanto, mutar um valor aninhado afeta ambas as cópias:
Rest vs Spread: Como Diferenciá-los
O token ... parece idêntico nos dois papéis, então use a posição para decidir qual você está lendo:
| Parâmetro rest | Spread syntax | |
|---|---|---|
| Onde aparece | Na lista de parâmetros de uma função | Em uma chamada, literal de array ou literal de object |
| O que faz | Reúne muitos valores em um único array | Expande um iterável/object em muitos valores |
Lado do = | Lado esquerdo (um alvo de desestruturação) | Lado direito (um valor sendo produzido) |
| Exemplo | function f(...args) {} | f(...args) |
Um teste simples: se ...x está recebendo valores, é rest; se está produzindo valores, é spread.
Combinando Parâmetros Rest e Spread Syntax
Os dois são imagens espelhadas, então se complementam naturalmente — rest coleta argumentos em um array na entrada, e spread expande um array em argumentos na saída:
Um padrão comum no mundo real é um wrapper que encaminha todos os argumentos para outra função:
Desestruturação com o Padrão Rest
Em uma atribuição por desestruturação, o padrão rest captura todas as propriedades ou elementos que você não nomeou explicitamente. Em objects, produz um object com as chaves restantes; em arrays, um array com os itens restantes.
Conclusão
O token ... é uma das adições mais úteis que o ES6 trouxe ao JavaScript. Como parâmetro rest, ele reúne um número variável de argumentos em um array limpo (e substitui o incômodo objeto arguments); como spread syntax, ele expande iteráveis em chamadas de função, literais de array e literais de object, proporcionando cópias superficiais e mesclagens concisas. Lembre-se das duas regras que mais pegam as pessoas de surpresa: um parâmetro rest deve ser o último parâmetro, e as cópias com spread são superficiais.
Tópicos Relacionados
- Atribuição por desestruturação — extraia valores de arrays e objects, frequentemente combinada com o padrão rest.
- JavaScript Array — a estrutura de dados que os parâmetros rest entregam a você e que o spread expande.
- Arrow functions revisitadas — por que as arrows dependem de parâmetros rest em vez de
arguments. - Vinculação de funções — controle de
this, frequentemente combinado com spread ao encaminhar argumentos.