Back to Course

    ๐Ÿ’ก Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:

    • Download Node.js to run JavaScript on your computer
    • Use your browser's Developer Console (Press F12) to test code snippets
    • Create a .html file with <script> tags and open it in your browser

    Deep Copy vs Shallow Copy & Data Structures

    Master memory management, reference handling, and data structure copying

    What You'll Learn in This Lesson

    • โœ“Reference vs Value types
    • โœ“Shallow copying pitfalls
    • โœ“Deep copying with structuredClone
    • โœ“JSON cloning dangers
    • โœ“Recursive copying algorithms
    • โœ“Immutable update patterns

    Understanding Reference vs Value

    Understanding how JavaScript handles data structures, memory, and copying is one of the most important skills for writing bug-free, scalable code. Many of the hardest-to-diagnose bugs come directly from not knowing whether you created a real copy or a shared reference.

    JavaScript stores values in two completely different ways: by value and by reference. Primitives such as numbers, strings, booleans, null, undefined, symbol, and bigint are stored by value, meaning each assignment creates a brand-new, independent copy. Objects, arrays, functions, Maps, Sets, and Dates are stored by reference, meaning multiple variables can point to the same memory.

    Reference vs Value

    Understand how primitives and objects are stored differently

    Try it Yourself ยป
    JavaScript
    // Primitives are stored by value
    let x = 10;
    let y = x;
    y = 20;
    
    console.log(x); // 10 โ€“ primitive types are fully independent
    
    // Objects are stored by reference
    let a = { score: 10 };
    let b = a;
    
    b.score = 99;
    console.log(a.score); // 99 โ€“ both point to the same reference
    
    // This is why you can break entire applications by accidentally 
    // modifying the original object when you thought you were modifying a copy

    ๐Ÿ’ก Key Insight: Understanding this distinction lets you debug faster, structure data correctly, and build cleaner architecture.

    Shallow Copying: The Hidden Trap

    A shallow copy duplicates only the top level of an object. It does not clone nested structures. JavaScript provides several shallow-cloning techniques that developers often assume are deep copies, which leads to subtle bugs.

    Shallow Copying

    Learn how shallow copies share nested objects

    Try it Yourself ยป
    JavaScript
    const user = { name: "Leo", prefs: { theme: "dark" } };
    const copy = { ...user };
    
    copy.prefs.theme = "light";
    
    console.log(user.prefs.theme); 
    // "light" โ€“ shallow copies share nested objects
    
    // Common shallow copy operations:
    // โ€ข Spread operator { ...obj }
    // โ€ข Object.assign({}, obj)
    // โ€ข Array methods like .slice(), .concat()
    
    const items = [
      { id: 1, qty: 1 },
      { id: 2, qty: 3 }
    ];
    
    const shallow = items.slice();
    shallow[0].qty = 99;
    
    console.log(items[0].qty); 
    // 99 โ€“ mutation leaked 
    ...

    โš ๏ธ Warning: These operations are fast and convenient, but unsafe when dealing with nested structures.

    Deep Copying: True Independence

    A deep copy creates a fully independent clone, duplicating every level of nesting so changes never leak back into the original structure.

    Why deep copies matter:

    • When working with complex UI state (React, Vue, Svelte)
    • When handling API responses before transforming them
    • When storing cached data
    • When building undo/redo history
    • When preventing reactivity bugs

    Deep Copying with structuredClone

    Create fully independent clones of nested data

    Try it Yourself ยป
    JavaScript
    // Modern JavaScript provides structuredClone()
    const user = { name: "Leo", prefs: { theme: "dark" } };
    const deep = structuredClone(user);
    
    deep.prefs.theme = "light";
    console.log(user.prefs.theme); 
    // "dark" โ€“ deep clone protects the original
    
    // Nested arrays example
    const cart = [{ item: "Book", qty: 1 }];
    const cloned = structuredClone(cart);
    
    cloned[0].qty = 5;
    console.log(cart[0].qty); // 1 โ€“ no mutation
    
    // structuredClone() handles:
    // โ€ข Dates, RegExp, Map, Set, ArrayBuffer
    // โ€ข Nested
    ...

    The JSON Cloning Trap

    Many developers use JSON cloning, but it's risky because it destroys important data:

    The JSON Cloning Trap

    Understand why JSON.parse/stringify destroys data

    Try it Yourself ยป
    JavaScript
    const user = {
      name: "Alex",
      joined: new Date(),
      greet: () => console.log("Hello"),
      score: Infinity,
      extra: undefined
    };
    
    // JSON cloning destroys data
    const cloned = JSON.parse(JSON.stringify(user));
    
    console.log(cloned);
    // {
    //   name: "Alex",
    //   joined: "2024-01-15T10:30:00.000Z", // Date โ†’ string
    //   // greet: removed (functions lost)
    //   score: null, // Infinity โ†’ null
    //   // extra: removed (undefined lost)
    // }
    
    // This makes JSON cloning unsuitable for anything beyond simp
    ...

    โŒ Avoid: JSON cloning destroys Dates, Functions, Infinity/NaN, Undefined, and Circular references.

    Building a Recursive Deep Clone

    If you want full control, building a recursive deep clone function is the most reliable approach for understanding how cloning actually works under the hood.

    Recursive Deep Clone

    Build your own deep clone function

    Try it Yourself ยป
    JavaScript
    function deepClone(value) {
      // Handle primitives and null
      if (value === null || typeof value !== "object") {
        return value;
      }
    
      // Handle arrays
      if (Array.isArray(value)) {
        return value.map(item => deepClone(item));
      }
    
      // Handle objects
      const clone = {};
      for (let key in value) {
        if (value.hasOwnProperty(key)) {
          clone[key] = deepClone(value[key]);
        }
      }
      return clone;
    }
    
    // Test it
    const original = { 
      x: 1, 
      y: { z: 2 },
      arr: [{ id: 1 }, { id: 2 }]
    };
    
    ...

    Real-World API Example

    Consider this common real-world situation: You fetch user data from an API and want to modify a piece of it for display without altering the original payload.

    Real-World API Example

    Protect API data from accidental mutation

    Try it Yourself ยป
    JavaScript
    // โŒ WRONG: Shallow copy causes silent mutation
    const apiData = {
      user: {
        name: "Eli",
        stats: { posts: 20, likes: 88 }
      }
    };
    
    const displayData = { ...apiData };
    displayData.user.stats.likes = 200;
    
    console.log(apiData.user.stats.likes); 
    // 200 โ€“ silently mutated original data!
    
    // โœ… CORRECT: Deep copy protects original
    const apiData2 = {
      user: {
        name: "Eli",
        stats: { posts: 20, likes: 88 }
      }
    };
    
    const clonedData = structuredClone(apiData2);
    clonedData.user.stats.likes = 
    ...

    Working with Maps and Sets

    Data structures like Maps and Sets need similar care. Developers often assume copying a Map protects data, but it only copies the key/value references.

    Working with Maps and Sets

    Deep clone Map and Set data structures

    Try it Yourself ยป
    JavaScript
    // โŒ Shallow copy of Map still shares nested objects
    const map = new Map();
    map.set("profile", { age: 18 });
    
    const copy = new Map(map);
    copy.get("profile").age = 40;
    
    console.log(map.get("profile").age); 
    // 40 โ€“ Map shallow copied, nested object shared
    
    // โœ… Deep cloning with structuredClone
    const map2 = new Map();
    map2.set("profile", { age: 18 });
    
    const deepMap = structuredClone(map2);
    deepMap.get("profile").age = 40;
    
    console.log(map2.get("profile").age);
    // 18 โ€“ original safe
    
    // Same patt
    ...

    Immutable Update Pattern

    A powerful real-world pattern is immutable updates, where instead of editing data in place, you clone, change the clone, and return it. This avoids mutation chains and keeps your application predictable.

    Immutable Update Pattern

    Clone, modify, and return for predictable state

    Try it Yourself ยป
    JavaScript
    // Immutable update pattern
    function updateScore(state, newScore) {
      const cloned = structuredClone(state);
      cloned.user.score = newScore;
      return cloned;
    }
    
    const initialState = {
      user: { name: "Sam", score: 100 },
      settings: { theme: "dark" }
    };
    
    const updatedState = updateScore(initialState, 250);
    
    console.log(initialState.user.score); // 100 โ€“ unchanged
    console.log(updatedState.user.score); // 250 โ€“ new state
    
    // This pattern is used heavily in:
    // โ€ข React state updates
    // โ€ข Redux redu
    ...

    ๐ŸŽฏ Pro Pattern: Immutable updates make state changes predictable and prevent cascading mutations across your app.

    Performance Considerations

    Reference sharing affects performance. Shallow copies are extremely fast because they only duplicate top-level references. Deep copies recursively duplicate all nested data, meaning the cost grows with data complexity.

    When to use shallow copying:

    • Replacing the outer object only
    • Maintaining shared references on purpose
    • Avoiding expensive deep-clone performance costs
    • Managing lightweight, flat data structures

    When to use deep copying:

    • Working with nested objects or arrays
    • Maintaining immutability in state management
    • Preventing unintended mutations
    • Building undo/redo systems or time-travel debugging

    Performance Considerations

    Choose the right copying strategy for your data

    Try it Yourself ยป
    JavaScript
    // Shallow copy: Fast but risky for nested data
    const shallow = { ...bigObject }; // O(n) for top level only
    
    // Deep copy: Slower but safe for nested data
    const deep = structuredClone(bigObject); // O(n * depth)
    
    // Choose based on data structure
    const flatData = { x: 1, y: 2, z: 3 };
    const shallowOK = { ...flatData }; // Safe, fast
    
    const nestedData = {
      user: { profile: { settings: { theme: "dark" } } }
    };
    const deepRequired = structuredClone(nestedData); // Necessary
    
    // Highly nested objec
    ...

    Common Mistakes to Avoid

    Understanding these common pitfalls will save you hours of debugging:

    Common Mistakes to Avoid

    Learn the pitfalls that cause mutation bugs

    Try it Yourself ยป
    JavaScript
    // โŒ MISTAKE 1: Partial deep copying
    const config = {
      theme: { mode: "dark" },
      languages: ["js", "python"]
    };
    
    const clone = { 
      ...config, 
      languages: [...config.languages] // deep copy array
    };
    
    clone.theme.mode = "light"; 
    // Still mutates original โ€” theme was shallow copied!
    
    // โœ… FIX: Deep copy everything consistently
    const fixed = structuredClone(config);
    fixed.theme.mode = "light";
    console.log(config.theme.mode); // "dark" โœ“
    
    // โŒ MISTAKE 2: Assuming slice() is safe for nested arra
    ...

    Mastery Summary

    Mastering deep and shallow copying is essential for writing reliable JavaScript:

    • โœ… Prevents hidden mutations and ghost bugs
    • โœ… Improves debugging and system stability
    • โœ… Keeps UI state consistent across frameworks
    • โœ… Strengthens your mental model of JavaScript memory
    • โœ… Essential for production-level applications

    Good developers write code that avoids unintended side effects. Great developers predict them before they happen. Understanding deep vs shallow copying lets you design safer functions, cleaner components, and more stable architectures.

    This is one of the most powerful skills for building production-level apps โ€” and one every serious developer must understand.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service