Boa noite Wesley.
A diferença é bem simples, na prática a mudança é no endereço de memória do objeto.
Exemplo:
const foo = {nome: 'Fulano', id: 1};
let bar = foo;
bar.id = 2;
console.log(foo.id); // OUTPUT: 2
console.log(bar.id); // OUTPUT: 2
Por estar referenciando o objeto 'foo' dentro do objeto 'bar' você acaba alterando a variável que está naquele endereço de memória, e não mudando apenas a variável em apenas um dos objetos.
Uma forma de prevenir isso é o Spread Operator (...).
Exemplo:
const foo = { nome: 'Fulano', id: 1 };
let bar = { ...foo };
bar.id = 2;
console.log(foo.id); // OUTPUT: 1
console.log(bar.id); // OUTPUT: 2
Dessa forma cada objeto possui diferentes endereços de memória e podem ser alterados sem alterar os demais.
Mas CUIDADO, esse regra não funciona para objetos aninhados!
Outras formas de usarmos o Spread Operator (...) é para a junção de objetos.
Exemplo:
const foo = { nome: 'Fulano', id: 1 };
const bar = { altura: 1.75, peso: 80 };
const pessoa = { ...foo, ...bar }
console.log(pessoa); // OUTPUT: { nome: 'Fulano', id: 1, altura: 1.75, peso: 80 }
Sugiro dar uma olhada nesse artigo do link abaixo para saber o poder de Rest / Spread Operator e de como eles podem facilitar sua vida
https://medium.com/trainingcenter/spread-operator-vs-rest-parameters-f8688d8e1761