Skip to Content
Course content

49: Structured Clone and Deep Copying

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you have a physical folder containing a project plan. Inside that folder, there's a smaller envelope containing a list of contact numbers. If you give a colleague a "shallow copy" of your folder, it's like giving them a shortcut or a link to your folder. If they open that envelope and scribble out a phone number, your original list is now ruined too, because you're both looking at the exact same piece of paper.

To actually protect your data, you need a "deep copy." This is the equivalent of taking every single page, every single envelope, and every single staple in that folder to a photocopier. You create a completely independent replica. Now, your colleague can scribble all over their copy, and your original remains pristine.

The Trap of the Shallow Copy

In JavaScript, we often use the spread operator ... to copy objects. It feels safe, but it's a shallow copy. It only copies the top-level properties. If those properties are other objects or arrays, JavaScript just copies the reference (the memory address), not the actual data.

const gameState = {
  player: "Hero",
  stats: { hp: 100, mp: 50 }
};

// A shallow copy using the spread operator
const savePoint = { ...gameState };

// Changing a top-level property is fine
savePoint.player = "Sidekick"; 

// But changing a nested object affects BOTH!
savePoint.stats.hp = 0;

console.log(gameState.stats.hp); // 0 - Oops, our original state is dead.

I can't tell you how many hours I've spent debugging "ghost" changes in my code because I forgot that nested objects are shared by reference. You change a value in a copy, and suddenly your original data source is mutated in ways that seem impossible.

The "JSON Hack" and its Flaws

For years, the community relied on a clever trick: JSON.parse(JSON.stringify(obj)). It works by turning the object into a string and then back into a new object, effectively stripping away all references. I'll be honest: it's a handy shortcut for simple data, but it's dangerous.

Why? Because JSON doesn't know what a Date object, a Map, a Set, or a RegExp is. If your object contains a Date, the JSON trick will turn it into a plain string, and you've just lost the ability to use date methods on that value. It also completely deletes any functions stored in the object.

The Modern Solution: structuredClone

Thankfully, we now have structuredClone(). This is a built-in global function designed specifically to handle deep copying without the baggage of the JSON hack. It handles nested arrays, objects, Dates, and even circular references (where an object refers back to itself), which would normally crash the JSON method.

const userProfile = {
  id: 1,
  details: {
    username: "dev_master",
    joined: new Date('2023-01-01')
  },
  preferences: new Set(['dark-mode', 'notifications-on'])
};

const clonedProfile = structuredClone(userProfile);

// Now we can mutate deeply nested data safely
clonedProfile.details.username = "new_username";
clonedProfile.preferences.add('beta-tester');

console.log(userProfile.details.username); // "dev_master" (Unchanged!)
console.log(userProfile.preferences.has('beta-tester')); // false (Unchanged!)

One quick heads-up: structuredClone isn't magic. It cannot clone functions or DOM elements. If you try to clone an object that contains a method, JavaScript will throw a DataCloneError. For most data-driven applications, though, this is exactly what you need.




📋 Practical Task

Implementing an Undo System for a User Profile Editor

You are building a profile editor where users can change their information. To prevent data loss, you need to implement a "Snapshot" feature. This allows the user to make changes to a temporary copy of their profile and only save them to the original object if they click "Confirm".

Your Task:

  • Create a currentProfile object that contains a nested settings object (e.g., { theme: 'light', notifications: true }) and a tags array.
  • Implement a function called createDraft() that uses structuredClone to create a deep copy of the currentProfile.
  • Modify a value inside the settings object of the draft.
  • Modify a value inside the tags array of the draft.
  • Log both the currentProfile and the draft to the console to prove that the original profile remained untouched while the draft was updated.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.