This distinction runs through nearly every method above (.slice(), spread, Object.assign()), so it's worth stating precisely once: a shallow copy duplicates the top-level container but still shares references to anything nested inside it; a deep copy duplicates everything, all the way down, so nothing is shared with the original.
const original = { user: { name: "Alice" }, tags: ["a", "b"] };
const shallow = { ...original }; // top-level keys copied, but .user and .tags are the SAME objects
shallow.user.name = "Bob";
console.log(original.user.name); // "Bob" — leaked through the shared nested reference
const deep = structuredClone(original); // every level is a genuinely independent copy
deep.user.name = "Carol";
console.log(original.user.name); // still "Bob" — completely unaffected
Every array/object copying technique covered in this reference — spread, .slice(), Object.assign(), .map() returning new objects — is shallow by default. Reach for structuredClone() (or a library's deep-clone utility) only when the data actually has meaningful nested structure that needs full independence; for flat data, a shallow copy is simpler and cheaper.