DEV Community

Cover image for Copying objects in JavaScript

Copying objects in JavaScript

Rohit Kumawat on June 06, 2020

Scenario: Whenever we pass objects between components as props or as arguments in function, we need to copy that object to make sure tha...
Collapse
 
sagar profile image
Sagar

There is a cool library available for cloning objects efficiently called rfdc (Really Fast Deep Clone).

const clone = require("rfdc")();

const user = {
  id: 1,
  name: "Leanne Graham",
  username: "Bret",
  email: "Sincere@april.biz",
  phone: "1-770-736-8031 x56442",
  website: "hildegard.org",
  company: {
    name: "Romaguera-Crona",
    catchPhrase: "Multi-layered client-server neural-net",
    bs: "harness real-time e-markets",
  },
};

const nextUser = clone(user);

console.log(user === nextUser); // This will return false because object have differnt reference.
Collapse
 
miketalbot profile image
Mike Talbot ⭐

The great thing about rfdc is that it super quickly clones real objects with cycles/functions/constructors etc. It is super quick at that.

If you need to quick clone something including enumerable properties but NOT any of that cool stuff rfdc does - then I use this that is a little quicker if you know that there won't be issues:

export function clone(o) {
    var newO, i

    if (typeof o !== 'object') {
        return o
    }
    if (!o) {
        return o
    }

    if (Array.isArray(o)) {
        newO = []
        for (i = 0; i < o.length; i += 1) {
            newO[i] = clone(o[i])
        }
        return newO
    }

    newO = {}
    for (i in o) {
        newO[i] = clone(o[i])
    }
    return newO
}

Collapse
 
sagar profile image
Sagar

Thanks, Mike for sharing this.

Collapse
 
sagar profile image
Sagar

looks good 👍🏻

Collapse
 
ip127001 profile image
Rohit Kumawat

Thanks for sharing!

Collapse
 
ip127001 profile image
Rohit Kumawat

Thanks for such a cool suggestion.
Infact after your comment, I have looked into it and its comparision with other libraries. I think it's very efficient.

Collapse
 
sagar profile image
Sagar

👍🏻

Collapse
 
bernardbaker profile image
Bernard Baker

Great article. Many of us encounter this problem and don't know how to resolve it. I've personally encountered it once or twice.

Collapse
 
ip127001 profile image
Rohit Kumawat • Edited

So there is a lodash library which gives cloneDeep() method to perfectly deep copy an object. Below an example attached:

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);

You can also visit this page to find more: lodash.com/docs/4.17.15#cloneDeep

Another approach is to use recursion.
make a custom function like one I have used to iterate on each key in object and if that key is also an object then again call the method to copy the keys.
Something like below:


function isObject(obj) {
  let type = typeof obj;
  return type === 'object';
};

function deepCopy(obj) {
  let copiedObj = {};
  for (let key in obj) {
    if (obj.hasOwnkeyerty(key)) {
      if (isObject(obj[key])) {
        copiedObj[key] = deepCopy(obj[key]);
      } else {
        copiedObj[key] = obj[key];
      }
    }
  }
  return copiedObj;
}
Collapse
 
papayankey profile image
Benneth Yankey • Edited

I surely will use the recursion approach too. However, typeof is sloppy in terms of differentiating between array and object. In order to truly check for object type, I will go with plain old trick below:

function isObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}
Thread Thread
 
ip127001 profile image
Rohit Kumawat

Cool. I missed that part. Thanks for the solution.

I was just giving some information about how can we make such a function to deep copying with help of recursion. So, there might be some more improvements that can be implemented to make it handle every case.

But Great Insight!

Thread Thread
 
bernardbaker profile image
Bernard Baker

That's a good point.

Collapse
 
ag251994 profile image
abhishek gupta

I have stopped using lodash. I will use the recursive function

Collapse
 
bernardbaker profile image
Bernard Baker

I like the recursive function.

Thread Thread
 
ip127001 profile image
Rohit Kumawat

Great! make your own common function to handle all cases.

Enjoy!

Collapse
 
gfabrizi profile image
Gianluca Fabrizi

Great article!
Just last week i encountered this same issue with some production code:
we had a video player that accepts some options when you initialize it; for some strange reasons if 2 video player where initialized on the same page, they both had the same value for some options passed only to the second player. The code is legacy, the videoplayer is implemented as a big fat object.
It turns out that the player store options for a particular feature in a nested object, so even if i clone the player itself with Object.assign(), the inner object is the same reference for both of them 😅 ...

Collapse
 
ip127001 profile image
Rohit Kumawat

😀 Interesting scenario!
I encountered this problem when I was passing down some data to child components but somehow it was changing data in parent component too.

Thanks for reading!

Collapse
 
ramvishvas profile image
Ramvishvas Kumar

Great article with great solution.

Collapse
 
ip127001 profile image
Rohit Kumawat

Thanks for reading!