In JavaScript, copying objects and arrays is a common task, but it’s not always straightforward. This is because objects and arrays are reference types, meaning when you assign them to a new variable with =
operator, you're often just copying the reference, not the actual data.
🤖 Meet QuirkyRobot
Say you have a robot:
let quirkyrobot = {
name: 'Chitti',
humaneProperties: {
heartRate: null,
emotions: undefined,
mood: 'curious'
},
technicalProperties: {
storage: '1 Zettabyte',
clockSpeed: '1 terahertz',
},
introduction: function(){
let greetings = `Hello! I am ${this.name} the robot. Speed: ${this.technicalProperties.clockSpeed}, Memory: ${this.technicalProperties.storage}`;
return greetings;
}
}
Now, If we want to create a copy of this, we would assign it to the new variable using =
operator.
let newrobot = quirkyrobot;
You're not creating a new robot; you're just pointing newrobot
to the same robot. Any changes to newrobot
will affect quirkyrobot
and vice versa. It's like having two names for the same person!
Example:
let newrobot = quirkyrobot;
newrobot.name = 'R2-D2';
console.log(quirkyrobot.name); // Outputs: 'R2-D2'
/* Above assignment of name property of newrobot has also modified
the original objects (quirkyrobot) name property since both objects
points to same reference */
Sometimes this behaviour is intentional. But when we want to deal with a fresh copy and have the old one untouched, we need to make a true copy from the original object.
1. 🛠️ Shallow Copy (Copying the Top-Level Properties)
A shallow copy means copying the top-level properties of an object. Nested objects or arrays will still reference the same memory location.
1.1. Using spread syntax of ES6 (...)
let shallowCopy = {...quirkyrobot};
shallowCopy.name = 'Wall-e';
console.log(quirkyrobot.name); // Outputs: 'Chitti'
console.log(shallowCopy.name); // Outputs: 'Wall-e'
1.2. Using Object.assign()
let shallowCopy = Object.assign({}, quirkyrobot);
shallowCopy.name = 'Wall-e';
console.log(quirkyrobot.name); // Outputs: 'Chitti'
console.log(shallowCopy.name); // Outputs: 'Wall-e'
Both methods created a new object with the same top-level properties. However, nested objects or arrays of new object still reference the same memory location of those nested structures of original object.
What that means is,
let shallowCopy = Object.assign({}, quirkyrobot);
shallowCopy.humaneProperties.mood = 'calm';
console.log(quirkyrobot.humaneProperties.mood);
/* Output: 'calm' but not 'curious' since shallowCopy object's nested
structures are still referencing the original object's nested
structures.*/
2. Deep Copy (Cloning Nested Structures)
A deep copy means creating a new object that doesn’t share any references with the original — including nested ones.
Let’s revisit our quirkyrobot and make a true copy this time.
2.1 Using JSON.parse(JSON.stringify())
:
let deepCopyRobot = JSON.parse(JSON.stringify(quirkyrobot));
deepCopyRobot.humaneProperties.mood = "happy";
console.log(quirkyrobot.humaneProperties.mood); // Outputs: 'curious'
console.log(deepCopyRobot.humaneProperties.mood); // Outputs: 'happy'
This method clones the entire object so changes inside nested properties don’t affect the original.
However, it has a few drawbacks:
- It cannot copy functions, undefined, or Symbol values.
- Special objects like Date, Map, or Set are converted to plain objects or strings.
- It fails on circular references.
In our case, the introduction()
method disappears in the copied object:
console.log(typeof deepCopyRobot.introduction); // undefined
So, while JSON.parse(JSON.stringify()) is great for simple objects, it’s not ideal for complex data.
2.2 structuredClone(): (ES6 native solution):
Modern JavaScript offers a built-in function:
let structuredRobot = structuredClone(quirkyrobot);
structuredRobot.humaneProperties.mood = "excited";
console.log(quirkyrobot.humaneProperties.mood); // 'curious'
Handles most of the javascript built-in types but fails with functions and class instances.
2.3 Using Utility Libraries like Lodash:
If you need something battle-tested:
let _ = require("lodash");
let clonedRobot = _.cloneDeep(quirkyrobot);
clonedRobot.humaneProperties.mood = "joyful";
console.log(quirkyrobot.humaneProperties.mood); // 'curious'
Lodash’s cloneDeep() handles almost every case — including nested arrays, objects, maps, and sets — while keeping your original object safe.
If you think your object/array is going to be nested, and you want to copy it to the core, then use Deep Copy/Clone. Else, stick to shallow copy.
Shallow copy is much faster than deep copy, so its advised to use it only when necessary.
References from the OG
MDN Shallow copy
MDN Deep copy
MDN Object.assign()
MDN Structured clone
✍️ Co-authored with: @hrithik_pasumarthi
Top comments (0)