Let’s start by understanding why we need to clone objects in JavaScript. When you assign an object to a new variable, you’re not creating a copy - you’re just creating another reference to the same object in memory.
The Problem: Assignment Doesn’t Create a Copy
const original = { a: 1, b: 2 };
const reference = original; // This is NOT a copy
reference.a = 999;
console.log(original); // Output: { a: 999, b: 2 }
console.log(reference); // Output: { a: 999, b: 2 }
As you can see, changing reference.a
also changed original.a
. That’s because they’re the same object! Let’s look at proper ways to clone objects.
1. Shallow Clone with Object.assign()
This method copies the top-level properties of an object.
const original = { a: 1, b: 2, c: 3 };
const clone = Object.assign({}, original);
// Modify the clone
clone.a = 999;
console.log(original); // Output: { a: 1, b: 2, c: 3 }
console.log(clone); // Output: { a: 999, b: 2, c: 3 }
2. Shallow Clone with Spread Operator (...
)
This is the modern and preferred way for simple objects.
const original = { a: 1, b: 2, c: 3 };
const clone = { ...original };
// Modify the clone
clone.a = 999;
console.log(original); // Output: { a: 1, b: 2, c: 3 }
console.log(clone); // Output: { a: 999, b: 2, c: 3 }
3. Deep Clone with JSON.parse()
and JSON.stringify()
This works for nested objects but has limitations (can’t handle functions, dates, undefined, etc.).
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = JSON.parse(JSON.stringify(original));
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
4. Deep Clone with Lodash Library
A robust solution for complex objects (requires installing Lodash).
// First install: npm install lodash
const _ = require('lodash');
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = _.cloneDeep(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
5. Deep Clone with Recursive Function
A custom implementation without external libraries.
function deepClone(obj) {
// Handle null, undefined, and primitive types
if (obj === null || typeof obj !== "object") return obj;
// Handle Date
if (obj instanceof Date) return new Date(obj);
// Handle Array
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
// Handle Object
const clonedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = deepClone(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
6. Deep Clone with structuredClone()
(Modern Browsers)
A new built-in method available in modern environments.
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = structuredClone(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
When to Use Each Method
- Shallow cloning (
Object.assign()
or...
) is sufficient when your object only contains primitive values (strings, numbers, booleans) - Deep cloning is needed when your object contains other objects or arrays as properties
- For production applications,
structuredClone()
(if available) or Lodash’scloneDeep()
are recommended for deep cloning - The JSON method is simple but has limitations with special data types
Let me verify the current status of structuredClone
support:
I’ll rewrite this blog post to make it easier to understand, with clear code examples and their outputs.
Let’s start by understanding why we need to clone objects in JavaScript. When you assign an object to a new variable, you’re not creating a copy - you’re just creating another reference to the same object in memory.
The Problem: Assignment Doesn’t Create a Copy
const original = { a: 1, b: 2 };
const reference = original; // This is NOT a copy
reference.a = 999;
console.log(original); // Output: { a: 999, b: 2 }
console.log(reference); // Output: { a: 999, b: 2 }
As you can see, changing reference.a
also changed original.a
. That’s because they’re the same object! Let’s look at proper ways to clone objects.
1. Shallow Clone with Object.assign()
This method copies the top-level properties of an object.
const original = { a: 1, b: 2, c: 3 };
const clone = Object.assign({}, original);
// Modify the clone
clone.a = 999;
console.log(original); // Output: { a: 1, b: 2, c: 3 }
console.log(clone); // Output: { a: 999, b: 2, c: 3 }
2. Shallow Clone with Spread Operator (...
)
This is the modern and preferred way for simple objects.
const original = { a: 1, b: 2, c: 3 };
const clone = { ...original };
// Modify the clone
clone.a = 999;
console.log(original); // Output: { a: 1, b: 2, c: 3 }
console.log(clone); // Output: { a: 999, b: 2, c: 3 }
3. Deep Clone with JSON.parse()
and JSON.stringify()
This works for nested objects but has limitations (can’t handle functions, dates, undefined, etc.).
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = JSON.parse(JSON.stringify(original));
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
4. Deep Clone with Lodash Library
A robust solution for complex objects (requires installing Lodash).
// First install: npm install lodash
const _ = require('lodash');
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = _.cloneDeep(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
5. Deep Clone with Recursive Function
A custom implementation without external libraries.
function deepClone(obj) {
// Handle null, undefined, and primitive types
if (obj === null || typeof obj !== "object") return obj;
// Handle Date
if (obj instanceof Date) return new Date(obj);
// Handle Array
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
// Handle Object
const clonedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = deepClone(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
6. Deep Clone with structuredClone()
(Modern Feature)
A new built-in method for deep cloning that’s supported in modern browsers . It’s available in Chrome 98+, Firefox 94+, Edge 98+, Safari 15.4+, and Node.js 17+ .
const original = {
a: 1,
nested: {
b: 2,
c: 3
}
};
const clone = structuredClone(original);
// Modify the nested property in clone
clone.nested.b = 999;
console.log(original.nested.b); // Output: 2
console.log(clone.nested.b); // Output: 999
When to Use Each Method
- Shallow cloning (
Object.assign()
or...
) is sufficient when your object only contains primitive values (strings, numbers, booleans) - Deep cloning is needed when your object contains other objects or arrays as properties
- For production applications,
structuredClone()
(if available in your environment) or Lodash’scloneDeep()
are recommended for deep cloning - The JSON method is simple but has limitations with special data types like functions and dates
- Custom recursive functions give you full control but require more code to handle all edge cases
The structuredClone()
method is becoming the standard way to deep copy objects in modern JavaScript environments .