JavaScript: What is the Difference Between a Deep Copy and a Shallow Copy?

In JavaScript Technology

In JavaScript most of the times we pass values by references, unless it is required to deal with primitives.

In the following example of code primitive values are 123, ‘bob’, true, null, undefined]:

let shallowArr = [123, 
                          'bob', 
                          true, 
                          null, 
                          undefined];

To understand the difference between shallow copying and deep copying need to know the difference between reference copy and object copy.

  • Reference copy: creates a copy of a reference variable pointing to an object.
  • Object copy: creates a copy of the object itself.

There are different methods to copy objects and each of them have different options.

Shallow Copy

The followings are methods to implement shallow copy:
1. arr1.slice(0)
2. [].concat(arr1)
3. Spread Operator
4. Object.create({}, obj)
5. Object.assign({}, obj)
6. Array.from(arr1)

Shallow copy method creates a copy of an object but doesn’t copy the inner objects/primitives.

Deep Copy

The followings are methods to implement deep copy:
1. JSON.parse(JSON.stringify())
2. Service Workers postMessage() onmessage
3. History API history.pushState(obj, title) history.state
4. Notification API new Notification(“title”, {data: obj} ).data
5. Build a custom recursive function

Deep copy creates a copy of entire object structure. As deep copying creates additional objects it is more complicated method as the references create a complicated graph hence why this method is more expensive to conduct.

The following code example will show the difference of shallow copy and deep copy in action. Code is copied from Steve Griffith’s github https://gist.github.com/prof3ssorSt3v3/3d99c75b12b0b5df9549d83f11a7f228. Watch also his video and subscribe to his account to learn more about copy methods.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Shallow vs Deep Copy</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="../video-pages/main.css">
</head>
<body>
    <header>
        <h1>Shallow vs Deep Copy</h1>
    </header>
    <main>
        <div id="output"></div>
    </main>    
    <script>
        /***********************
        In NodeJS we only have the JSON methods.
        Beyond that you will have to bring in
        an NPM module or write your own
        custom method.
        ***********************/
        /***********************
        Deep Copy methods
        1. JSON.parse(JSON.stringify())
        2. Service Workers postMessage() onmessage
        3. History API history.pushState(obj, title) history.state
        4. Notification API new Notification("title", {data: obj} ).data
        5. Build a custom recursive function
        ***********************/
        
        let shallowArr = [123, 
                          'bob', 
                          true, 
                          null, 
                          undefined];
        
        let deepArr = [123, 
                       'bob', 
                       true, 
                       ['Hank', 'Brent', 'Lacy'], 
                       {'Rouleau':'Dog River', 
                        'Wilcox': 'Woolerton'}
                      ];
        
        let deepObj = {
            'characters': ['Wanda','Davis','Emma','Karen'],
            'places': ['Corner Gas','Ruby','Foo Mart'],
            'grad68': false,
            'seasons': 5
        }
        
        let newObj = {...deepObj};
        //newObj.places[0] = 'Ottawa'; //changed inside ref.
        //newObj.places = ['Ottawa', 'Calcutta']; //new ref
        console.log(newObj, deepObj);
        let otherObj = JSON.parse(JSON.stringify(deepObj));
        otherObj.places[0] = 'Ottawa';
        console.log(otherObj, deepObj);
        
        /*********************
        Shallow Copy Method examples
        1. arr1.slice(0)
        2. [].concat(arr1)
        3. Spread Operator
        4. Object.create({}, obj)
        5. Object.assign({}, obj)
        6. Array.from(arr1)
        *********************/
        let s = 'steve';
        let g = s;
        s = 'new value';
        //console.log(s, g);
        
        let arr = Array.from(shallowArr);
        //let arr1 = [...shallowArr];
        shallowArr[0] = 456;
        //console.log(arr, shallowArr);
        
    </script>
</body>
</html>