If you plan on coding with JavaScript, you need to understand how objects work. They’re one of the most important elements of JavaScript and a deep (pun intended 😉) understanding of objects will always be handy. Especially when cloning an object, it isn’t as simple as it might seem.
You need to clone an object if you don’t want to mutate your original object. For example, if you have a function that takes in an object and alters it, you probably don’t want to mutate your original object.
Check out this other post on Alligator.io on JavaScript objects if you're looking for a quick crash course.

So let’s create an object in JavaScript:
let testObject = {
a: 1,
b: 2,
c: 3
};
In the above code snippet, we initialize a new object and assign it to the variable testObject
. Now for most beginners, they’ll try to create a copy of this object to manipulate in their code by assigning the testObject
to a new variable. I’ve personally been guilty of this for longer than I care to admit.
Below is a code snippet that shows why that won’t work.
let testObject = {
a: 1,
b: 2,
c: 3
};
// Creating a new variable that 'copies' our testObject
let testObjectCopy = testObject;
testObject.a = 9;
console.log(testObjectCopy.a);
// This returns a = 9
As shown in the code snippet above, creating the new variable testObjectCopy
doesn’t actually create a copy of testObject
. Instead, it’s simply referencing the testObject
. Any changes you make to the assumed copy will reflect in the original object as well.
Looping through the object and copying each property to a new object wouldn’t work either.
const copyObject = object => {
// This is the object that will store the original object's properties
let copiedObj = {};
for (let key in object) {
// This copies each property from the original object to the copy object
copiedObj[key] = object[key];
}
return copiedObj;
};
const testObject = {
a: 5,
b: 6,
c: {
d: 4
}
};
copyObject(testObject);
There are several issues with the approach above:
- Point 1. A loop that copies each property to a new object would only copy enumerable properties on the object. Enumerable properties are properties that will show up in
for
loops andObject.keys
. - Point 2. The copied object has a new
Object.prototype
method, which is not what you want when you copy an object. - Point 3. If your object has a property that is an object, your copied object will actually refer to the original instead of creating an actual copy. This means that if you change that nested object in the copied object, the original gets changed as well.
- Point 4. Any property descriptors are not copied. If you set things like
configurable
orwritable
tofalse
, the property descriptors in the copied object will default totrue
.
So How Can I Copy an Object the Right Way?
For simple objects that only stores primitive types like numbers and strings, shallow copying methods like the one above will work. However, if your object features references to other nested objects, the actual object won’t be copied. You would only be copying the reference.
For a deep copy, the easiest option is to use reliable external libraries like Lodash.
Using Lodash Clone And Clonedeep
Lodash comes with two different functions that allow you to do shallow copies and deep copies. These are clone
and clonedeep
. The great thing about Lodash is that you can import each function individually, without requiring the entire library into your project. This can wildly reduce the size of your dependencies.
const clone = require('lodash/clone');
const cloneDeep = require('lodash/clonedeep');
// You could also do:
// const clone = require('lodash.clone');
// const cloneDeep = require('lodash.clonedeep');
// Depends on your style :)
Now to use the clone
and clonedeep
function, here’s some code to try out:
const clone = require('lodash/clone');
const cloneDeep = require('lodash/clonedeep');
const externalObject = {
animal: 'Gator'
};
const originalObject = {
a: 1,
b: 'string',
c: false,
d: externalObject
};
const shallowClonedObject = clone(originalObject);
externalObject.animal = 'Crocodile';
console.log(originalObject);
console.log(shallowClonedObject);
// The `animal` property in both the originalObject and shallowClonedObject
// are both changed this way since it's a shallow copy.
const deepClonedObject = clonedeep(originalObject);
externalObject.animal = 'Lizard';
console.log(originalObject);
console.log(deepClonedObject);
// The 'animal' property in the originalObject changes, but for the
// deepClonedObject, it remains as 'Crocodile' since it copied
// the entire object separately instead of copying the reference.
In the above code, we create our object called originalObject
, which stores 7 properties with different values in each. The property d
references our externalObject
which has the property of animal
and a value of 'Gator'
.
When we do the clone
function from Lodash, it creates a shallow copy of the object, which we assign to shallowClonedObject
. Assigning the animal
property in our externalObject
a new value will change both the originalObject
and the shallowClonedObject
because the shallow clone was only able to copy the reference to the externalObject
. It didn’t create a brand new object for itself.
This is where the clonedeep
function comes in. If you do the same process above for the deepClonedObject
, the originalObject
’s d
property is the only one to change.
🤓 Try it out and see how this can help your code! 🚀