DEV Community

Petros Koulianos
Petros Koulianos

Posted on • Originally published at levelup.gitconnected.com on

Proper Ways to Clone an Object in JavaScript

Photo by Bimata Prathama on Unsplash

Objects in JavaScript are reference values and can store complex key-value properties.

let story = {
    title: 'Proper Ways to Copy(Clone) an Object in JavaScript',
    author:{
            name:'pkoulianos',
            email:'petran@pkoulianos.com'
    },
    tags:['Javascript','programming']
};
Enter fullscreen mode Exit fullscreen mode

Copy an object can be a little tricky. But donโ€™t worry about in this story weโ€™ll cover how to copy an object in proper ways.

1. The Fatal๐Ÿ˜ก Way to Copy an Object

A fatal way to try copying an object is to use the assign = operator. The reason is that the assign operator will only pass the reference to the new variable.

Letโ€™s see a simple example

let car1 = { color:โ€™whiteโ€™, type:โ€™4X4'};// fatal way to copy an object
let car2 = car1;//change the color property
car2.color = โ€˜redโ€™;console.log(car1);
**//{ color: 'red', type: '4X4' }** ๐Ÿ˜‚๐Ÿ˜‚
console.log(car2);
**//{ color: 'red', type: '4X4' }** ๐Ÿ˜‚๐Ÿ˜‚
Enter fullscreen mode Exit fullscreen mode

In the above example, we create a new object car1 and try to copy it with the = operator to a new variable car2 and we change the color property. Printing both objects we can see that is identical and the reason is that both car1 and car2 have the same reference of the object.

2. Get a Shallow๐Ÿ’ง copy

Shallow copy will copy all enumerable own properties from the source object to the target.

In simple terms, a shallow copy will not truly copy :

  1. Arrays, Sets, etc
  2. Inner objects

Get a shallow copy with Object.assign()

Object.assign() will get you a shallow copy of your target object:

let post = {
   title:'How to copy objects in JS',
   tags:['js','js-basics','programming'],
   date: new Date(),
   author:{
         name:'petros',
         email:'petran@pkoulianos.com'
   },
   getAuthorData: function(){
              return this.author.name+'-'+this.author.email;
   }
};let newPost = Object.assign({},post);
newPost.title = 'I love js'
newPost.tags[0] = 'web-programming'
newPost.author.name = 'Petran';
newPost.date = new Date(1970);console.log(post);
console.log(newPost);//console output
{ title: 'How to copy objects in JS',
  tags: ['web-programming', 'js-basics', 'programming'],
  date: 2020-07-21T18:48:29.112Z,
  author: { name: 'Petran', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' },
  getAuthorData: [Function: getAuthorData] }
{ title: 'I love js',๐Ÿ˜€
  tags: ['web-programming', 'js-basics', 'programming'],๐Ÿ˜‚
  date: 1970-01-01T00:00:01.970Z,๐Ÿ˜€
  author: { name: 'Petran', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' },๐Ÿ˜‚
  getAuthorData: [Function: getAuthorData] }๐Ÿ˜€
Enter fullscreen mode Exit fullscreen mode

In the above example, we create a new object post and copy it with Object.assign() to a new variable newPost and we change all properties. Printing both objects we can see that the shallow copy newPost have copied properly the title ,date and getAuthorData but tags and author are pass by reference.

Get a shallow copy with โ€ฆSpread operator

The spread operator will get you also a shallow copy of your target object:

/ \*\*\* / 
**let newPost = {...post}**
/ \*\*\* /
console.log(post);
console.log(newPost);//console output
{ title: 'How to copy objects in JS',
  tags: ['web-programming', 'js-basics', 'programming'],
  date: 2020-07-21T18:48:29.112Z,
  author: { name: 'Petran', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' },
  getAuthorData: [Function: getAuthorData] }
{ title: 'I love js',
  tags: ['web-programming', 'js-basics', 'programming'],
  date: 1970-01-01T00:00:01.970Z,
  author: { name: 'Petran', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' },
  getAuthorData: [Function: getAuthorData] }
Enter fullscreen mode Exit fullscreen mode

3. Get a Deep๐ŸŒŠ copy

A deep copy of an object will solve the mystery of getting a proper copy of inner objects and arrays, sets, etc but date objects will be converted to string and functions will not be copied at all.

We can get a deep copy by using the JSON object.

let targetObj = JSON.parse(JSON.stringify(sourceObj));

/ \*\*\* / 
let newPost = JSON.parse(JSON.stringify(post));
/ \*\*\* /
console.log(post);
console.log(newPost);//console output
{ title: 'How to copy objects in JS',
  tags: ['js', 'js-basics', 'programming'],
  date: 2020-07-21T18:54:35.964Z,
  author: { name: 'petros', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' },
  getAuthorData: [Function: getAuthorData] }
{ title: 'I love js',
  tags: ['web-programming', 'js-basics', 'programming'],
  date: **'2020-07-21T18:54:35.964Z'** ,๐Ÿ˜‚
  author: { name: 'Petran', email: '[petran@pkoulianos.com](mailto:petran@pkoulianos.com)' } }
Enter fullscreen mode Exit fullscreen mode

Printing both objects we can see that the deep copy newPost have copied properly the title , tags and author but date is converted to string and getAuthorData are not copied at all.

5. Conclusion

Both Shallow and Deep copies have their own pros and cons. Before we decide which copy is right, we have to be sure about the object properties.

References


Top comments (1)

Collapse
 
stevescruz profile image
Steve Cruz

When I was a beginner some years ago, I would've loved to have read such a clear written explanation. I used to get many errors related to shallow copies.