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.
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' π±
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! π)
β οΈ 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 π
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);
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
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)