Lodash: Clone vs CloneDeep

Share:

Posted under Let’s Fix, where we discuss problems and solutions to real world web dev problems

I ran into an interesting prssdsasdoblem today at work that involved shallow vs deep cloning of an array.

I wanted to duplicate the value of an array of objects two times then loop through them and modify a value from each object along the way.

var thing1 = [
  {
    id: 1
  },
  {
    id: 2
  },
  {
    id: 3
  },
  {
    id: 4
  },
  {
    id: 5
  }
];

var thing1Clone = _.clone(thing1);
var list = thing1.concat(thing1Clone);

console.log(list[0]===list[10]); //true, WUT?

_.each(list, function(item) {
  console.log(item.id);
  item.id += 4000;
})

The output of this code is

true
1
2
3
4
5
4001
4002
4003
4004
4005

Soooo, the code looped through first 5 items of list, which is an concatenation of thing1 and its clone thing1Clone, then by the time it got to the second set of items, it seemed to use the value of the items after they’ve been incremented by 4000.

What? Why did it evaluate true for list[0] === list[10]? Why did the browser think they’re the same???

Puzzled by this, I asked a friend for pointers and he suggested a possible issue with referencing. So I looked up Array.concat and see if I can find anything there, I ended up at MDN and the definition provided by [MDN] was:

Object references (and not the actual object): concat copies object references into the new array. Both the original and new array refer to the same object. That is, if a referenced object is modified, the changes are visible to both the new and original arrays.

Bingo! that explains it, they were concatenated by reference….but wait, I thought I cloned it and set it to a new variable, so why was it still making reference to the old array??

So I went to [Lodash’s doc] and looked up _.clone, and found this:

_.clone(): Creates a shallow clone of value.

and right there in the doc:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// → true

Naturally this makes sense now, and right next to _.clone() was _.cloneDeep():

This method is like _.clone except that it recursively clones value.

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// → false

 

And here’s the implementation of _.clone() and _.cloneDeep() from Lodash (you’ll have to jump around the function calls to truly understand it, I’m still reading it at the moment):
https://github.com/lodash/lodash/blob/master/dist/lodash.js#L2233-L2281

I hope you find this useful the next time you have to do Array.concat on an array with a copy of itself. Use _.cloneDeep() !!

Comments Or Questions? Discuss In Our Discord

If you enjoyed this tutorial, make sure to subscribe to our Youtube Channel and follow us on Twitter @pentacodevids for latest updates!

More from PentaCode