03-javascriptTermsLevel_07Shallow Copy vs Deep Copy

Shallow Copy vs Deep Copy

Level 7 — Objects & Prototypes Copying top-level vs fully nested structures.


1. Prerequisites


2. Term Category

Language Core (Universal: Works everywhere): Shallow Copy vs Deep Copy is a fundamental concept in this technology stack. Level 7 — Objects & Prototypes


3. Explanation

(1) Design Motivation — "Why did we design this?"

Since standard assignments (let copy = original) copy only reference pointers, developers need ways to create genuine duplicates of objects to avoid mutating original state (highly critical in frameworks like React). However, objects often contain nested arrays or other objects.

To duplicate objects, we must choose between two copy semantics:

Shallow Copy

A shallow copy duplicates only the top-level properties of the object. If the object contains nested objects or arrays, the shallow copy copies their reference pointers. Therefore, the copy and the original share the same nested structures.

  • Methods: Spread syntax (const copy = { ...original }) or Object.assign({}, original).

Deep Copy

A deep copy recursively traverses the entire object tree and duplicates every nested object and array at every level, creating a completely independent data clone. Modifying any nested element in the copy has no effect on the original.

  • Methods: JSON.parse(JSON.stringify(original)) (legacy helper) or the modern built-in structuredClone(original) Web API (supported globally in Node.js 17+ and modern browsers).

(2) Reality Metaphor

Imagine a house blueprint.

  • Shallow Copy is like copying the blueprint page. You change the front door color (top-level property) on the copy. But the blueprint has a drawing label pointing to a "Community Swimming Pool" down the street (nested object reference). If you draw a slide on the pool drawing, the physical shared pool changes for both blueprints.
  • Deep Copy is like building a completely new replica house in a different town, including a brand new replica swimming pool. Drawing a slide on the new pool has no effect on the original community pool.

(3) JavaScript Code Examples

Shallow Copy Nesting Bug

const userA = {
  name: "Alice",
  details: { age: 25 } // Nested object!
};

// 1. Create a shallow copy using spread syntax
const userB = { ...userA };

userB.name = "Bob"; // Modify top level
userB.details.age = 30; // Modify nested level

console.log(userA.name);        // "Alice" (Top-level copy worked!)
console.log(userA.details.age); // 30! (Nested object was shared by reference!)

Deep Copy Solution (Modern structuredClone)

const userA = {
  name: "Alice",
  details: { age: 25 }
};

// 2. Create a true deep copy using structuredClone
const userB = structuredClone(userA);

userB.name = "Bob";
userB.details.age = 30;

console.log(userA.name);        // "Alice" (Untouched)
console.log(userA.details.age); // 25 (Untouched! Nested object was duplicated)

4. Common Mistakes & Pitfalls

Mistake 1: Relying on Spread Syntax ... for Deep Nesting (e.g. state updates)

The mistake: Using { ...state } in React or state managers, and modifying nested fields directly.

Why it's wrong: Spread syntax is strictly a shallow copy. Modifying nested properties directly mutates the original parent state, which breaks component state tracking.

Incorrect:

const state = { list: ["taskA", "taskB"], user: "Admin" };
const copy = { ...state };
copy.list.push("taskC"); // Mutates state.list!

Fix:

const state = { list: ["taskA", "taskB"], user: "Admin" };
// Option A: Spread at every nested level
const copy1 = { ...state, list: [...state.list] }; 

// Option B: Deep clone
const copy2 = structuredClone(state); 

Mistake 2: Losing Context Binding (this) in Shallow Vs Deep Copy Callbacks

The mistake: Passing methods from Shallow Vs Deep Copy instances as standalone callbacks to timers or event listeners without explicitly binding this.

Why it's wrong: Extracting object methods disassociates them from their target parent instance, causing this to resolve to undefined (in strict mode) or window/globalThis at runtime.

Incorrect:

const obj = {
    name: "shallow_vs_deep_copy",
    log() { console.log(this.name); }
};
setTimeout(obj.log, 100); // ❌ Output: undefined (loses object context)

Fix:

const obj = {
    name: "shallow_vs_deep_copy",
    log() { console.log(this.name); }
};
setTimeout(() => obj.log(), 100); // Correct: Arrow function captures lexical context

Mistake 3: Unhandled Asynchronous Failures in Shallow Vs Deep Copy Operations

The mistake: Executing asynchronous operations within Shallow Vs Deep Copy without wrapping await calls in try...catch blocks or chaining .catch().

Why it's wrong: Unhandled promise rejections trigger UnhandledPromiseRejectionWarning in Node.js or unhandled rejection errors in modern browsers, leaving application state in corrupted or uncoordinated states.

Incorrect:

async function processData() {
    const res = await fetch("/api/shallow_vs_deep_copy"); // ❌ Unhandled network failure crashes execution flow
    const data = await res.json();
    return data;
}

Fix:

async function processData() {
    try {
        const res = await fetch("/api/shallow_vs_deep_copy");
        if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);
        return await res.json();
    } catch (err) {
        console.error(`Caught error in shallow_vs_deep_copy: ${err.message}`);
        return null;
    }
}

5. Practice Exercises

Exercise 1: Shallow Copy Spread vs Deep Copy via structuredClone()

Scenario: A state management library compares shallow object copying with spread ({ …obj }) against deep cloning with structuredClone().

Requirements:

  1. Create nested state object.
  2. Perform shallow copy and deep copy via structuredClone().
  3. Mutate nested property in copies.
  4. Verify shallow mutates source while deep copy isolates source.
Answer

Implementation

function demonstrateCopying(originalState) {
  const shallowCopy = { ...originalState };
  const deepCopy = structuredClone(originalState);

  shallowCopy.nested.value = "SHALLOW_MUTATED";

  return {
    sourceValue: originalState.nested.value,
    deepValue: deepCopy.nested.value
  };
}

// Verification tests
const state = { title: "App", nested: { value: "ORIGINAL" } };
const res = demonstrateCopying(state);

console.assert(res.sourceValue === "SHALLOW_MUTATED", "Test 1 Failed: Shallow copy must mutate source nested reference");
console.assert(res.deepValue === "ORIGINAL", "Test 2 Failed: Deep copy must remain isolated");

Technical Explanation

  1. Shallow Copying ({ …obj }): Shallow copying copies top-level properties but retains shared references to nested objects/arrays.
  2. structuredClone() Standard: Browser/Node standard structuredClone(obj) creates deep clones of complex objects, Maps, Sets, and Arrays.
  3. Mutation Isolation: Deep copies guarantee changes to nested properties do not alter source objects.

Exercise 2: Shallow Vs Deep Copy Advanced Context Handler

Scenario: A web application component processes shallow vs deep copy data operations within enterprise workflows.

Requirements:

  1. Write handleShallowVsDeepCopySecondary(target, options).
  2. Validate target input.
  3. Apply domain updates.
  4. Return boolean status.
Answer

Implementation

function handleShallowVsDeepCopySecondary(target, options) {
  if (!target) return false;
  const opts = options || {};
  target.status = opts.status || "VERIFIED";
  return true;
}

// Verification tests
const mockTarget = {};
console.assert(handleShallowVsDeepCopySecondary(mockTarget, { status: "VERIFIED" }) === true, "Test 1 Failed");
console.assert(mockTarget.status === "VERIFIED", "Test 2 Failed");

Technical Explanation

  1. Shallow Vs Deep Copy Architecture: Applying shallow vs deep copy patterns structures complex application components.
  2. Defensive Parameter Guarding: Guards functions against null/undefined dereference errors.
  3. Standard Conformance: Conforms to standard ECMAScript / DOM specifications.

Exercise 3: Shallow Vs Deep Copy Performance Optimization

Scenario: An application utility optimizes shallow vs deep copy execution to prevent performance bottlenecks.

Requirements:

  1. Write optimizeShallowVsDeepCopyTertiary(collection).
  2. Validate collection input.
  3. Filter invalid items.
  4. Return clean collection.
Answer

Implementation

function optimizeShallowVsDeepCopyTertiary(collection) {
  if (!Array.isArray(collection)) return [];
  return collection.filter(item => item !== null && item !== undefined);
}

// Verification tests
const list = [10, null, 20, undefined, 30];
const clean = optimizeShallowVsDeepCopyTertiary(list);
console.assert(clean.join(",") === "10,20,30", "Test 1 Failed");

Technical Explanation

  1. Shallow Vs Deep Copy Optimization: Optimizing shallow vs deep copy improves application throughput.
  2. Garbage Collection Memory Cleanup: Reclaims unneeded memory allocations efficiently.
  3. Cross-Browser Reliability: Delivers consistent behavior across modern browser engines.


7. Key Takeaways

  • Shallow copies only copy top-level properties; nested objects/arrays are shared by reference.
  • Deep copies duplicate all properties recursively, creating entirely independent objects.
  • Spread syntax ... and Object.assign perform shallow copies.
  • structuredClone() is the modern, built-in standard API for performing deep copies.
  • Avoid using JSON.stringify serialization on objects containing Dates, functions, or custom class instances, as they will get coerced or deleted.
Built with LogoFlowershow