This page looks best with JavaScript enabled

Cloning objects in Javascript

 ·   ·  ☕ 3 min read

Cloning objects is easier than ever before, but you have to remember a few nuances.

We will discuss about two ways to clone/copy an object -

  1. Deep copy: copy object so that any subsequent changes to new object does not reflect in older object
  2. Shallow copy: copy props and child objects of an object, but the new object keeps pointing to the original

Both have their uses.

Spread operator

The quickest way to deep copy is using the spread ... operator.

1
2
3
4
5
6
7
8
const earth = {
  position: 3,
  components: { water: "71%", land: "29%" }
};

const secondEarth = { ...earth };
console.log(secondEarth);
// { position: 3, components: { water: '71%', land: '29%' } }

This is quick and efficient. ... also copies values rather than reference for primitives.

The catch - objects within the object you copied will have references copied over and not values. In other words ... acts like a deep copy for primitives but shallow copy for objects.

Continuing our earlier example -

1
2
3
4
5
6
7
secondEarth.position = 10;
secondEarth.components.water = "50%";

console.log(secondEarth);
// { position: 10, components: { water: '50%', land: '29%' } }
console.log(earth);
// { position: 3, components: { water: '50%', land: '29%' } }

Object.Assign()

Object assign behaves similar to the spread operator. It has the same advantages and quirks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const earth = {
  position: 3,
  components: { water: "71%", land: "29%" }
};

const secondEarth = {};
Object.assign(secondEarth, earth);
console.log(secondEarth);
// { position: 3, components: { water: '71%', land: '29%' } }

secondEarth.position = 10;
secondEarth.components.water = "50%";

console.log(secondEarth);
// { position: 10, components: { water: '50%', land: '29%' } }
console.log(earth);
// { position: 3, components: { water: '50%', land: '29%' } }

In addition to what was said earlier: note that both ... and Object.assign() work for circular objects, i.e., a child object referring to itself. This makes absolute sense since the objects are not “deep copied” any way.

External Libraries

Use libraries like loadash to deep clone objects.

1
2
3
4
5
6
7
const cloneDeep = require("lodash.clonedeep");
var secondearth = _.cloneDeep(earth);

console.log(secondEarth);
// { position: 10, components: { water: '50%', land: '29%' } }
console.log(earth);
// { position: 3, components: { water: '71%', land: '29%' } }

Use JSON.stringify()

Convert your object to string, and back to object. Works well but can result in data loss - for e.g. dates are not converted properly, undefined can mess up things, any regular expressions do not convert as expected, and so on.

1
2
3
4
5
6
var secondEarth = JSON.parse(JSON.stringify(earth));

console.log(secondEarth);
// { position: 10, components: { water: '50%', land: '29%' } }
console.log(earth);
// { position: 3, components: { water: '71%', land: '29%' } }

In addition to all the problems highlighted above, JSON.stringify() is also very slow.

Custom clone

You could write 4-5 lines of code to clone your objects and make it specific for your use case.Circular referencing, nested objects and complex things beyond grasp of humanity can make your life hell.

This way you are free to treat your objects with the respect they deserve.

Recommendation

  • Use ... for the most part for shallow copy
  • Use one of the packaged libraries to create deep clones

Also see

Stay in touch!
Share on

Prashanth Krishnamurthy
WRITTEN BY
Prashanth Krishnamurthy
Technologist | Creator of Things