Difference between Shallow copy and Deep copy in JavaScript

Shallow copy

When we create a copy of any object and some fields of original object are referencing to other objects, then just the reference address are copied to the new object. So if you will change something in the copied object then it will change in the original object and vice versa. Let’s see some examples.

For Objects

const phoneObj = {model: 'Apple', version: 'iPhone X'};

const copyObj = phoneObj;

copyObj.model = 'Samsung';

console.log(phoneObj); // {model: 'Samsung', version: 'iPhone X'}

console.log(copyObj); // {model: 'Samsung', version: 'iPhone X'}

For Arrays

const phones = ['Apple', 'Samsung', 'Nokia', 'OnePlus'];

const copyPhones = phones;

copyPhones.push('Redmi');

console.log(phones); // ['Apple', 'Samsung', 'Nokia', 'OnePlus', 'Redmi'];

console.log(copyPhones); // ['Apple', 'Samsung', 'Nokia', 'OnePlus', 'Redmi'];

So to overcome this problem, we need to deep copy objects and arrays.

Deep Copy

If we copy an object or array and all the level properties are copied without any references, then it is a Deep copy.

There are some methods (Object.assign(), spread operator and slice()) which can deep copy only the top level properties. That means these methods do not work for multi level objects or arrays.

Using Object.assign() for single level objects:

const phone = {model: 'Apple', version: 'iPhone X'};

const copyPhone = Object.assign({}, phone);

console.log(copyPhone); // {model: 'Apple', version: 'iPhone X'};

Using spread operator (…) for single level objects:

const phone = {model: 'Apple', version: 'iPhone X'};

const copyPhone = {...phone};

console.log(copyPhone); // {model: 'Apple', version: 'iPhone X'};

//For Arrays
const phones = ['Apple', 'Samsung', 'OnePlus'];

const copyPhones = [...phones];

console.log(copyPhones); // ['Apple', 'Samsung', 'OnePlus'];

Using slice() method for Array:

const phones = ['Apple', 'Samsung', 'OnePlus'];

const copyPhones = phones.slice(0);

console.log(copyPhones); // ['Apple', 'Samsung', 'OnePlus'];

Object.assign() for multi level objects

const phone = {
    brand: 'Apple',
    storage: {
        ram: '8GB',
        memory: '128GB'
    }
};

const copyPhone = Object.assign({}, phone);

copyPhone.brand = 'Samsung';
// brand will be changed only for copy object

copyPhone.storage.memory = '64GB';
// memory will be changed to 64 for both original and copy object

console.log(phone); 
// {brand: 'Apple', storage:{ram: '8GB', memory: '64GB'}}

console.log(copyPhone); 
// {brand: 'Samsung', storage:{ram: '8GB', memory: '64GB'}}

Let’s see how we can achieve deep cloning for multi level objects also in JavaScript.

Using recursive function:

To deep clone an object, you need to iterate through each property and check if the current property contains an object. If yes, then do a recursive call to the same function by passing the current property’s value (i.e. the nested object). Look at the below example.

const phone = {
      brand: 'Apple',
      storage: {
          ram: '8GB',
          memory: '128GB'
      }
};

function makeDeepClone(phone) {
    let newObject = {};
    Object.keys(phone).map(key => {
        if(typeof phone[key] === 'object'){
            newObject[key] = makeDeepClone(phone[key]);
        } else {
            newObject[key] = phone[key];
        }
  });

  return newObject;
}

const copyPhone = makeDeepClone(phone);

copyPhone.brand = 'Samsung';

copyPhone.storage.memory = '64GB';

console.log(phone); 
// {brand: 'Apple', storage:{ram: '8GB', memory: '128GB'}}

console.log(copyPhone); 
// {brand: 'Samsung', storage:{ram: '8GB', memory: '64GB'}}

Using JSON.stringify() and JSON.parse():

First convert your original object into string and then parse it back to JSON object from it.

const phone = {
    brand: 'Apple',
    storage: {
        ram: '8GB',
        memory: '128GB'
    }
};

const copyPhone = JSON.parse(JSON.stringify(phone));

copyPhone.brand = 'Samsung';

copyPhone.storage.memory = '64GB';

console.log(phone); 
// {brand: 'Apple', storage:{ram: '8GB', memory: '128GB'}}

console.log(copyPhone); 
// {brand: 'Samsung', storage:{ram: '8GB', memory: '64GB'}}

This technique (JSON.parse(JSON.stringify(obj))) doesn’t work if your object property contains function as value. Because when you JSON.stringify the object, the property containing function as value gets removed from the object. So go for recursive function approach in such case.

You have learnt various ways to clone object and arrays in JavaScript. While cloning always check what type of object or array you are cloning, so carefully choose your cloning method by keeping the object structure in mind.

Reference

Difference between JSON.parse() and JSON.stringify()

Leave a Reply

Your email address will not be published. Required fields are marked *