O spread expande um objeto dentro de outro
A sintaxe de spread de objetos no JavaScript — aqueles três pontinhos antes de um objeto — copia as propriedades enumeráveis próprias desse objeto para dentro do objeto literal que está ao redor. É o caminho mais curto para clonar, mesclar e gerar cópias modificadas sem mexer no original.
copy tem as mesmas chaves e valores de user, mas é um objeto diferente. Alterar um não afeta o outro — pelo menos no nível mais externo. Já já voltamos nessa ressalva.
O modelo mental é o seguinte: { ...obj } significa "despeje as propriedades de obj dentro deste novo objeto literal". Tudo o que você escrever junto com o spread vira parte do resultado.
Clonar e sobrescrever em uma única etapa
O padrão mais comum é espalhar um objeto e, em seguida, adicionar ou sobrescrever algumas propriedades. Como as últimas chaves prevalecem, você faz o spread primeiro e sobrescreve depois:
user fica intacto. updated é um novo objeto com o role substituído. Esse padrão de atualização imutável aparece em todo lugar no JavaScript moderno — updaters de estado do React, reducers do Redux, qualquer código que prefira não mutar direto.
Inverta a ordem e o comportamento se inverte também:
Aqui o role: "guest" vem primeiro, então user.role acaba sobrescrevendo ele. Útil quando você quer definir valores padrão que o objeto espalhado pode substituir.
Mesclando objetos com spread
Para mesclar objetos em JavaScript, basta espalhar dois (ou mais) objetos dentro de um novo literal. Os objetos que vêm depois sobrescrevem os anteriores quando há chaves conflitantes:
theme e fontSize vêm de userPrefs; debug passa direto de defaults. Três objetos? Quatro? A regra é a mesma — leia na ordem em que aparecem, e quem escreve por último vence.
Essa é a forma moderna de substituir Object.assign({}, defaults, userPrefs). As duas fazem a mesma coisa, mas a versão com spread é mais fácil de ler e ainda evita aquele bug clássico de escrever Object.assign(defaults, userPrefs) — que acaba mutando o próprio defaults.
Spread faz cópia rasa (shallow copy)
Aqui é onde muita gente se perde. O spread copia apenas as propriedades do primeiro nível do objeto. Se o valor de uma propriedade for outro objeto ou um array, o que se copia é a referência, não o conteúdo.
Alterar copy.address.city também alterou user.address.city — isso acontece porque os dois objetos compartilham o mesmo objeto address. O spread só criou uma nova "casca" externa.
Quando você precisa modificar algo aninhado, aplique o spread em cada nível que quer alterar:
Para um clone realmente profundo de qualquer estrutura de dados, use structuredClone(obj). Ele dá conta de objetos aninhados, arrays, datas, maps e sets — e já vem embutido em todos os runtimes modernos.
Spread vs. rest
Os dois usam os mesmos três pontinhos, mas fazem o oposto um do outro. O spread expande; o rest agrupa.
Regra prática: se o ... aparece antes do = (na desestruturação), é rest. Se aparece dentro de um literal de objeto ou array depois do =, é spread.
Removendo uma propriedade de forma imutável
Juntando o rest na desestruturação com o spread de objetos, dá pra gerar uma cópia de um objeto sem uma determinada chave — sem precisar de delete e sem mutar nada:
tempToken é extraído para uma variável própria (que você ignora), e todo o resto cai em safe. O user original permanece intacto.
O que o spread não copia
Alguns detalhes importantes que vale conhecer:
- Propriedades não enumeráveis não são copiadas. A maioria das propriedades que você cria é enumerável por padrão, mas aquelas definidas com
Object.definePropertye algumas propriedades nativas não são. - O prototype não vem junto. Fazer
{ ...instance }te devolve um objeto simples, e não uma instância da classe original. Métodos definidos no prototype da classe não estarão na cópia. - Getters são executados. Ao espalhar um objeto que tem um getter, ele é chamado uma vez e o valor retornado é armazenado como uma propriedade comum no novo objeto.
copy tem x e y, mas é um objeto comum — o método distance vive em Point.prototype, e o spread não toca nisso. Quando você precisa clonar uma instância de classe, normalmente é a própria classe que tem que fornecer um método clone.
A seguir: métodos de array
O spread é só uma peça do kit de ferramentas para trabalhar com dados imutáveis. A outra peça importante são os métodos de array — map, filter, reduce e companhia —, que criam arrays novos em vez de alterar os originais. É isso que vem na próxima página.
Perguntas frequentes
O que o ...obj faz no JavaScript?
Dentro de um literal de objeto, ...obj copia todas as propriedades próprias enumeráveis daquele objeto para o novo objeto. { ...user } gera um objeto novinho com as mesmas chaves e valores de user. É a forma padrão de clonar ou mesclar objetos sem mexer nos originais.
Como mesclar dois objetos no JavaScript?
Faça o spread dos dois dentro de um novo literal de objeto: const merged = { ...a, ...b }. As propriedades de b sobrescrevem as chaves iguais que vieram de a, porque quem aparece depois vence. O resultado é equivalente a Object.assign({}, a, b), mas fica bem mais legível.
O spread de objetos faz cópia profunda?
Não. O spread de objetos é uma cópia rasa (shallow copy) — ele copia só as propriedades do primeiro nível, enquanto objetos e arrays aninhados continuam compartilhados por referência. Alterar copy.address.city também altera original.address.city. Para uma cópia profunda de verdade, use structuredClone(obj).
Qual a diferença entre spread e rest?
Escrevem-se iguais (...), mas fazem coisas opostas. O spread expande um objeto ou array em propriedades ou elementos individuais: { ...user }. Já o rest agrupa o que sobrou em uma única variável: const { name, ...others } = user. É o contexto que indica qual dos dois você está vendo.