DEV Community

3 Ways to Clone Objects in JavaScript

Samantha Ming on July 22, 2019

Because objects in #JavaScript are references values, you can't simply just copy using the =. But no worries, here are 3 ways for you to clone an...
Collapse
 
nmhillusion profile image
nmhillusion

Also have some issues when clone object with JSON.parse(JSON.stringify)
Can you check?

class Person {
  #name = "";
  constructor(name) {
    this.#name = name;
  }

  greet() {
    console.log("hi, " + this.#name);
  }
}

const p = new Person("Peter");

const obj = { d: new Date(), p };
const newObj = JSON.parse(JSON.stringify(obj));

console.log(typeof obj.d); // output: object
console.log(typeof newObj.d); // output: string

obj.p.greet(); // output: hi, Peter
newObj.p.greet(); // Uncaught TypeError: newObj.p.greet is not a function
Collapse
 
samanthaming profile image
Samantha Ming • Edited

I should of mentioned...the JSON method won’t be able to clone methods 😣

Check out this article, it has more info:
google.ca/amp/s/scotch.io/bar-talk...

Collapse
 
nmhillusion profile image
nmhillusion

Thank you,
And I have some questions about this,
When I copy:

const obj = {n1: 3, n2: new Number(4)};
const newObj = JSON.parse(JSON.stringify(obj));

console.log(typeof obj.n1); // number
console.log(typeof obj.n2); // object

console.log(typeof newObj.n1); // number
console.log(typeof newObj.n2); // number

obj.n2 and newObj.n2 are the same?

And as in my previous comment, when I copy:

const obj = {d: new Date()};
const newObj = JSON.parse(JSON.stringify(obj));

console.log(typeof obj.d); // object
console.log(typeof newObj.d); // string

Another question, when I create an object by Object.create like this:

const obj = Object.create({}, { "p": {readable: false, value: 11 }});
const newObj = JSON.parse(JSON.stringify(obj));

console.log(obj.p); // 11
console.log(newObj.p); // undefined

Why that, we cannot clone it without readable it? Please help me understand, thank you!

Collapse
 
patrickjsmirnov profile image
Dmitriy Smirnov

What is difference between spread and object.assign?

Collapse
 
adameier profile image
adam meier • Edited

I'ts important to note that Object.assign is a function which modifies and returns the target object. In Samantha's example using the following,

const cloneFood = Object.assign({}, food)
Enter fullscreen mode Exit fullscreen mode

{} is the object that is modified. The target object is not referenced by any variable at that point, but because Object.assign returns the target object, we are able to store the resulting assigned object into the cloneFood variable. We could switch our example up and use the following:

const food = { beef: '🌽', bacon: 'πŸ₯“' };

Object.assign(food, { beef: 'πŸ₯©' });

console.log(food);
// { beef: 'πŸ₯©', bacon: 'πŸ₯“' }
Enter fullscreen mode Exit fullscreen mode

Obviously the value of beef in our food object is wrong, so we can assign the correct value of beef using Object.assign. We aren't actually using the returned value of the function at all, but we are modifying our target object which we have referenced with the const food.

Spread on the other hand is an operator which copies properties of one object into a new object. If we wanted to replicate the above example using spread to modify our variable food...

const food = { beef: '🌽', bacon: 'πŸ₯“' };

food = {
  ...food,
  beef: 'πŸ₯©',
}
// TypeError: invalid assignment to const `food'
Enter fullscreen mode Exit fullscreen mode

...we get an error, because we use spread when creating new objects, and therefore are assigning a whole new object to food which was declared with const, which is illegal. So we can either choose to declare a new variable to hold our new object in, like the following:

const food = { beef: '🌽', bacon: 'πŸ₯“' };

const newFood = {
  ...food,
  beef: 'πŸ₯©',
}

console.log(newFood);
// { beef: 'πŸ₯©', bacon: 'πŸ₯“' }
Enter fullscreen mode Exit fullscreen mode

or we could declare food with let or var which would allow us to assign a whole new object:

let food = { beef: '🌽', bacon: 'πŸ₯“' };

food = {
  ...food,
  beef: 'πŸ₯©',
}

console.log(food);
// { beef: 'πŸ₯©', bacon: 'πŸ₯“' }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
patrickjsmirnov profile image
Dmitriy Smirnov

Got it. Thank you!

Collapse
 
samanthaming profile image
Samantha Ming

Thanks for chiming in and helping answer this question. This is great, let me add it to the code notes πŸ™‚

Collapse
 
spykelionel profile image
Ndi Lionel

Thu explanation is swift. Thanks

Collapse
 
evolutionxbox profile image
Jonathan Cousins

I don't think there is a difference aside from syntax in this case. The triple dot expression ... also means rest which does not mean Object.assign.

For more information see 2ality.com/2016/10/rest-spread-pro...