AlgoInsight

Q&A

Deep copying vs. shallow copying

By AlgoInsight Team2026-06-18

Overview

Copying an object seems simple until you realize objects can contain other objects. Shallow copy gives you a new container with the same nested references; deep copy gives you a completely independent tree. The right choice depends on whether you want changes to nested data to propagate or be isolated.

graph TD
    A[Original: {name, address:{city,zip}}] --> B[Shallow copy]
    A --> C[Deep copy]
    B --> D["New top-level object<br/>but address IS THE SAME OBJECT"]
    C --> E["Entirely new object<br/>address is a NEW object too"]
    D --> F["Mutate copy.address.city → changes original too!"]
    E --> G["Mutate copy.address.city → original unchanged ✓"]
    style E fill:#1e1b4b,color:#fff

The Core Difference Illustrated

Python

import copy

original = {"name": "Ada", "scores": [90, 85, 78]}

# Shallow copy
shallow = original.copy()           # or dict(original) or {**original}
shallow["name"] = "Linus"           # OK - doesn't affect original
shallow["scores"].append(100)       # ⚠ ALSO modifies original["scores"]!
print(original["scores"])           # [90, 85, 78, 100]  - unexpected!

# Deep copy
deep = copy.deepcopy(original)
deep["scores"].append(999)
print(original["scores"])           # [90, 85, 78, 100]  - untouched ✓

JavaScript

const original = { name: "Ada", address: { city: "London" } };

// Shallow copy (Object.assign or spread)
const shallow = { ...original };
shallow.name = "Linus";            // primitive - doesn't affect original
shallow.address.city = "Paris";    // ⚠ same nested object - original also changed!

// Deep copy (structuredClone - modern, built-in)
const deep = structuredClone(original);
deep.address.city = "Berlin";      // original.address.city stays "Paris"

Java

// Shallow: clone() (default Object.clone() copies top-level fields)
// Deep: implement Cloneable + clone all nested, or use serialization,
//       or copy constructors, or libraries (Jackson, Kryo).

Shallow Copy Methods by Language

Language Shallow copy
Python obj.copy(), list[:], dict(d), {**d}, copy.copy()
JavaScript {...obj}, Object.assign({}, obj), [...arr]
Java Object.clone() (default), copy constructors
C++ Copy constructor (default memberwise = shallow)

Deep Copy Methods by Language

Language Deep copy
Python copy.deepcopy(obj)
JavaScript structuredClone(obj) (modern), JSON.parse(JSON.stringify(obj)) (limited)
Java Implement Cloneable recursively, or serialization, or libraries
C++ Override copy constructor to deep-copy pointers

JavaScript: JSON round-trip limitations

JSON.parse(JSON.stringify(obj))
// Loses: undefined, functions, Date (becomes string), Map/Set, circular refs
// Use structuredClone() instead for real deep copies

When to Use Which

Why This Matters in Interviews

This is one of the highest-frequency conceptual questions across all languages. The signal: clearly explain that shallow copy shares nested references (so mutations to nested data affect both), while deep copy creates a fully independent clone. Giving a concrete broken-shallow-copy example, showing the fix (language-appropriate deep copy), and naming the trade-offs (deep copy costs O(n) vs shallow O(1)) shows mastery. Every language has language-specific gotchas - mention them for whatever stack the role uses.

Common Pitfalls

References

More answers