DEV Community

Mattia Rollo
Mattia Rollo

Posted on • Edited on

Objects: The Guide to Shallow vs. Deep Copy

Cloning a variable in JavaScript seems simple, right? If you are working with primitive values (like strings, numbers, or booleans), it works exactly as you expect:

let name = 'Pippo';
let newName = name; 

// newName is now 'Pippo'
// It is completely independent from the 'name' variable.
Enter fullscreen mode Exit fullscreen mode

However, if you try to do the same with Objects (or Arrays), things get tricky. This happens because in JavaScript, objects are assigned by REFERENCE, not by value.

Think of it like a house address: the variable doesn't contain the house itself, it just holds the address to find it. If you copy that address to another variable, you still have only one house. If you paint the walls blue using the second variable, the first variable will see a blue house too.

Let's look at an example:

// We create an object. 
// The variable 'student' holds a REFERENCE to this object in memory.
let student = {
    firstName: 'Mattia',
    lastName: 'Rollo',
    skills: {
        music: 5,
        coding: 5,
    }
};

// ❌ WRONG WAY TO CLONE
// This doesn't create a new object. It just copies the reference.
const cloneStudent = student;

// If we modify the clone...
cloneStudent.firstName = 'Pippo';

// ...the original changes too!
console.log(student.firstName); // Output: 'Pippo' 😱

Enter fullscreen mode Exit fullscreen mode

So, how do we properly clone objects?
We need to create a copy that is independent of the original. There are two types of copying in JavaScript: Shallow Copy and Deep Copy.

Shallow Copy (Good for simple objects)
A "Shallow Copy" creates a new object, but it only copies the properties at the first level. We can do this using the Spread Syntax (...) or Object.assign().

let student = {
    firstName: 'Mattia',
    lastName: 'Rollo'
};

// βœ… CORRECT (For simple objects)
// We use the Spread Syntax to create a new object
const cloneStudent = { ...student };

student.firstName = 'Pippo';

console.log(student.firstName);      // 'Pippo'
console.log(cloneStudent.firstName); // 'Mattia' (It didn't change! πŸŽ‰)

Enter fullscreen mode Exit fullscreen mode

⚠️ The Trap: Nested Objects

Shallow copies have a weakness. If your object contains another object inside it (nested), the spread syntax won't clone the inner object. It will still copy the reference for that inner part.

let student = {
    firstName: 'Mattia',
    skills: { 
        music: 10, 
        coding: 10 
    }
};

const cloneStudent = { ...student };

// If we change a nested property...
cloneStudent.skills.music = 0;

// ...it changes in the original too!
console.log(student.skills.music); // Output: 0 😭
Enter fullscreen mode Exit fullscreen mode

Deep Copy (The real solution)
To fix this, we need a Deep Copy. This means cloning the object and recursively cloning every child object inside it.


The Classic Way: Lodash

For years, developers relied on external libraries like Lodash. It’s a battle-tested solution.

// Assuming you imported lodash as '_'
const cloneStudent = _.cloneDeep(student);
Enter fullscreen mode Exit fullscreen mode

The Modern Way: structuredClone() (Recommended for 2025)

Good news! You don't always need an external library anymore. Modern JavaScript engines now support a native method called structuredClone(). It works natively in browsers and Node.js.

let student = {
    firstName: 'Mattia',
    skills: { 
        music: 10, 
        coding: 10 
    }
};

// βœ… THE MODERN SOLUTION
const cloneStudent = structuredClone(student);

cloneStudent.skills.music = 0;

console.log(student.skills.music);      // 10 (Safe!)
console.log(cloneStudent.skills.music); // 0
Enter fullscreen mode Exit fullscreen mode

Conclusion

  • Assignment (=): Copies the reference. Both variables point to the same object.

  • Shallow Copy (...spread): Great for simple objects, but fails with nested data.

  • Deep Copy (structuredClone): The robust way to create a completely independent copy, including nested objects.

Top comments (0)