Cả hai đều copy nông (shallow): chỉ sao chép các thuộc tính own enumerable ở tầng một.
Object lồng bên trong vẫn dùng chung tham chiếu.
const a = { user: { name: 'An' }, tags: ['x'] };
const b = { ...a };
b.user.name = 'Bình';
console.log(a.user.name); // 'Bình' → a bị sửa theoĐây là nguồn bug kinh điển trong React/Redux: tưởng đã tạo state mới nhưng object con vẫn là cũ, so sánh tham chiếu không phát hiện thay đổi.
Copy sâu: dùng structuredClone (có sẵn trong trình duyệt hiện đại và Node 17+). Nó giữ được Date, Map, Set, ArrayBuffer và cả tham chiếu vòng.
const deep = structuredClone(a);Cách cũ JSON.parse(JSON.stringify(obj)) làm mất undefined, Date biến thành chuỗi, và ném lỗi với tham chiếu vòng — chỉ dùng khi dữ liệu chắc chắn là JSON thuần.
Khác biệt nhỏ giữa spread và Object.assign: spread tạo object mới, Object.assign(target, src) ghi vào target và kích hoạt setter trên target; spread thì định nghĩa thuộc tính mới, không gọi setter.