Shallow Vs Deep Copy In Javascript
Tags: javascript, 100daysofcode, codenewbie, programming
Published: 2021-02-28 17:48:35

Hey, JS Developers!! While coding at least once you encounter a scenario where you need to copy an object or an array in Javascript. But sometimes it doesn't work as you expected.

In this article we'll cover the following concepts in detail:

- Create a copy of Primitive Data types
- Create a copy of Non-primitive data types
- Shallow Copy
- Methods to create a shallow copy of Array 
- Methods to create a shallow copy of Object
- Deep Copy
- Methods to create a deep copy

Let's get started!! 🚀🚀

## 🔢 Numbers

First, consider the simplest case of *Numbers* datatype.

```javascript
// Case 1: Copy Numbers

let marks = 100;
let total = marks;  // copy marks into total
console.log(marks, total);

marks = 200; // change the value of marks
console.log(marks, total);

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614521320135/9kWRHImAY.png)

It will work as expected.

## 🧵 Strings

```javascript
// Case 2: Copy Strings

let name = 'JS';
let name2 = name; //copy name into name2
console.log(name, name2);

name = 'blogs';
console.log(name, name2);

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614521616154/-VUCV-wi2.png)


As you noticed in the above two scenarios if you change the value of an original variable it does not affect the other variable.

When you create these values, they are tightly coupled with the variable they are assigned to. They only exist once. That means you do not really have to worry about copying **primitive data types** in JavaScript. When you make a copy, it will be a real copy. 

## 📝 Arrays

Now let's see how it works in the case of Arrays:

```javascript
// Case 3: Copy Arrays

let list = ['a', 'b', 'c', 'd'];
let box = list;
console.log("list-> ",list, "box-> ", box);

console.log("After changing some values ")

list[3] = 'e';
box[4] = 'f';
console.log("list-> ",list, "box-> ", box);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614522453400/ci9mOdv9u.png)

Wait what😲😲?? It doesn't yield the result we expected. If we update the array `box` it also changes the original array `list`. But why???

Because `box` is not a separate array, it is just a reference to the original array `list`. So whenever you update any of the arrays `list` or `box` it's always going to update the same reference. 

But what we do if we don't want this behavior and only want to update our copied array without affecting the original one? 

So here **Shallow Copy** comes into the picture.

## Shallow Copy

> Shallow copy is a bit-wise copy of an object. A new object is created that has an exact copy of the values in the original object. If any of the fields of the object are references to other objects, just the reference addresses are copied i.e., only the memory address is copied.

*Using shallow copy, we can copy a value that is non-primitive (Array or Object), and ideally, all the values inside that array or object are primitive.*

Let's explore some of the methods to make a copy of Arrays:

## Methods to copy an Array :

### 👆 Method 1: use `slice()`

```javascript
// Method 1: Use slice()

let list = ['a', 'b', 'c', 'd'];
let box = list.slice();
console.log("list-> ",list, "box-> ", box);

console.log("After changing some values ")

list[2] = 'e';
box[3] = 'f';
console.log("list-> ",list, "box-> ", box);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614523540294/Bq9UomkJ1.png)

### ✌️ Method 2: use `concat()`

```javascript
let list = ['a', 'b', 'c', 'd'];
let box = [].concat(list); // Method 2: Use concat()

console.log("list-> ",list, "box-> ", box);

console.log("After changing some values ")

list[2] = 'e';
box[3] = 'f';
console.log("list-> ",list, "box-> ", box);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614523540294/Bq9UomkJ1.png)


### 🤟Method 3: ES6 Spread operator

```javascript
let list = ['a', 'b', 'c', 'd'];
let box = [...list]; // Method 3: ES6 Spread operator

console.log("list-> ",list, "box-> ", box);

console.log("After changing some values ")

list[2] = 'e';
box[3] = 'f';
console.log("list-> ",list, "box-> ", box);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614523540294/Bq9UomkJ1.png)

### 🖖Method 4: Array.from()

```javascript

let list = ['a', 'b', 'c', 'd'];
let box = Array.from(list); // Method 4: Array.from()

console.log("list-> ",list, "box-> ", box);

console.log("After changing some values ")

list[2] = 'e';
box[3] = 'f';
console.log("list-> ",list, "box-> ", box);

```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614523540294/Bq9UomkJ1.png)


## 🪕 Objects

Now let's try to understand the concept of shallow & deep copy in the case of Objects.

```javascript
let student = {
    subject: 'JS',
    marks: 100
}

let record = student;

console.log("student",student, "record", record);
console.log("After changing some values ")

student.subject = 'Java';
record.marks = 50;
console.log("student", student, "record", record);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614529437755/Y3MHH1yQl.png)

Ohh!! It shows the same behavior as Arrays. If we modify the `record` or `student` objects, changes are reflected on both of them. Because both of the objects refer to the same memory location.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614529820544/7L3wdBI4n.png)

Then how do we make a copy of an object🤔? Let's explore some of them:

## Methods to copy an Object :

### 👆 Method 1: use `Object.assign()`

```javascript
let student = {
    subject: 'JS',
    marks: 100
}

let record = Object.assign({},student); //Method 1: Use Object.assign()

console.log("student",student, "record", record);
console.log("After changing some values ")

student.subject = 'Java';
record.marks = 50;
console.log("student", student, "record", record);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614530205328/aGgM2UfCm.png)

### ✌️ Method 2: use `spread operator`

```javascript
let student = {
    subject: 'JS',
    marks: 100
}

let record = {...student}; //Method 2: Use ES6 Spread Operator

console.log("student",student, "record", record);
console.log("After changing some values ")

student.subject = 'Java';
record.marks = 50;
console.log("student", student, "record", record);

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614530628402/_G7ecla7o.png)

So this is how **Shallow Copy** works.

Then what is **Deep Copy** and why do we use it? 🧐🧐

## Deep Copy

Now let's explore in-depth what is Deep copy and why do we use it.

> Deep copy is a process in which the copying process occurs recursively. It means first constructing a new collection object and then recursively populating it with copies of the child objects found in the original. In the case of deep copy, a copy of an object is copied into another object.

Let's try to understand this using an example:

```javascript
let student = {
    subject: 'JS',
    marks: 100,
    details: {
        name: 'developer',
        age: 23
    }
}

let record = {...student}; //Method 2: Use ES6 Spread Operator

console.log("student",student, "\nrecord", record);

console.log("After changing some values ")
student.details.age = 30;
record.marks = 50;
console.log("student", student, "\nrecord", record);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614531378377/uR2Z_6WIF.png)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614531415963/KwDpg9273.png)

As you noticed above when you change the value of `age` using `student.details.age = 30;` the change is reflected in both the objects.

But Why? 

If you see the `student` object is having **non-primitive** values. It has a nested Object. Unlike the previous examples, this object did not have all primitive values in it. So, exactly in this kind of scenario, if we want to create a new copy of the `student`, shallow copying will no longer work.

In the above example, a separate copy is created for primitive values like `subject` & `marks` but `details` is a non-primitive value & its reference is stored instead of creating a new copy.

So, in order to copy all the sub-non-primitive values of a non-primitive value such as `student`, we need to use a copying technique called **Deep Copying**.

```javascript
let student = {
    subject: 'JS',
    marks: 100,
    details: {
        name: 'developer',
        age: 23
    }
}

let record = JSON.parse(JSON.stringify(student)); //Deep Copy

console.log("After changing some values ")

student.details.age = 30;
record.marks = 50;
console.log("student", student, "\nrecord", record);
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1614532267830/4vjpRQSkt.png)

Now as you noticed in the above example, we have successfully copied the entire `student` object including its non-primitive nested objects values.

## Summary

- You really don't have to worry about copying primitive data types (strings/numbers) in JavaScript. When you make a copy, it will be a real copy.
- Shallow copy is used to copy a non-primitive value such as array/object, which has all values of primitive type. 
- Deep Copy is also used to copy a non-primitive value such as an array/object which has non-primitive values in it such as a nested array/object.

## Wrap Up!!

Thank you for your time!! Let's connect to learn and grow together.

[LinkedIn](https://www.linkedin.com/in/anuradha-aggarwal-4a2751107/) [Twitter](https://twitter.com/Anuradh06359394)

[![Buy-me-a-coffee](https://cdn.buymeacoffee.com/buttons/v2/default-blue.png)](https://www.buymeacoffee.com/anuradha2612)