Shallow copy vs deep copy

JavaScript

The short answer

A shallow copy creates a new object but only copies the first level of properties. If a property is an object or array, the copy still points to the same reference as the original. A deep copy creates a completely independent copy where every level is duplicated — changing the copy will never affect the original.

Why this matters

In JavaScript, objects and arrays are stored by reference, not by value. When you assign an object to a new variable, you are not creating a copy — both variables point to the same object in memory.

const original = { name: 'John', age: 30 };
const copy = original;
copy.name = 'Jane';
console.log(original.name); // "Jane" — the original changed too!

Both original and copy point to the same object. Changing one changes the other. This is why we need to know how to properly copy objects.

Shallow copy

A shallow copy creates a new object and copies all the top-level properties. But if a property holds a reference to another object, only the reference is copied, not the object itself.

const original = {
name: 'John',
address: {
city: 'New York',
zip: '10001',
},
};
const shallow = { ...original };
shallow.name = 'Jane';
console.log(original.name); // "John" — not affected
shallow.address.city = 'Boston';
console.log(original.address.city); // "Boston" — affected!

The name property is a string (a primitive), so it gets copied properly. But address is an object, so only the reference was copied. Both original.address and shallow.address point to the same object in memory.

Common ways to create a shallow copy:

// Spread operator
const copy1 = { ...original };
// Object.assign
const copy2 = Object.assign({}, original);
// For arrays
const arrCopy1 = [...originalArray];
const arrCopy2 = originalArray.slice();

All of these only create shallow copies.

Deep copy

A deep copy duplicates everything — every level, every nested object. The copy is completely independent from the original.

const original = {
name: 'John',
address: {
city: 'New York',
zip: '10001',
},
};
const deep = structuredClone(original);
deep.address.city = 'Boston';
console.log(original.address.city); // "New York" — not affected

Common ways to create a deep copy:

1. structuredClone (recommended)

const deep = structuredClone(original);

This is the modern and recommended way. It handles nested objects, arrays, dates, maps, sets, and more. It is built into the browser and Node.js.

2. JSON.parse + JSON.stringify

const deep = JSON.parse(JSON.stringify(original));

This works for simple objects, but it has problems. It does not handle undefined, functions, Date objects (they become strings), Map, Set, or circular references. Use structuredClone instead.

When to use which

Shallow copy is fine when:

  • Your object only has primitive values (strings, numbers, booleans)
  • You only need to change top-level properties
  • You are working with simple state objects in React

Deep copy is needed when:

  • Your object has nested objects or arrays
  • You need to make sure changes to the copy never affect the original
  • You are working with complex data structures

Common Pitfalls

A very common mistake candidates make is using the spread operator to copy an object with nested values, thinking they have a full copy. They then modify a nested property and the original changes too. This is a frequent source of bugs in React where you spread state to create a "new" object, but nested properties still point to the same reference.

// Common React bug
const [user, setUser] = useState({
name: 'John',
address: { city: 'New York' },
});
// This does NOT deep copy address
const newUser = { ...user };
newUser.address.city = 'Boston';
// original user.address.city is now also "Boston"
// Correct way
const newUser = {
...user,
address: { ...user.address, city: 'Boston' },
};

Interview Tip

When answering this question, always show an example with nested objects to clearly demonstrate the difference. Mention structuredClone as the modern solution for deep copy, and explain why JSON.parse(JSON.stringify()) is not always reliable. If the interview is React-focused, bring up the common bug of spreading nested state — interviewers love candidates who can connect concepts to real problems.

Why interviewers ask this

This question tests your understanding of how references work in JavaScript. It comes up all the time in real code, especially in React where immutability is important. Interviewers want to see if you know the difference, if you can pick the right approach for the situation, and if you are aware of the common bugs that happen when you accidentally create a shallow copy when you needed a deep one.