JS review - JS light copy and deep copy


A shallow copy copies only one layer, while a deeper object level copy copies only references.
Deep copy has multiple layers, and data at each level will be copied.

Generally speaking, it is assumed that B copies A. when a is modified, if B changes, it is a shallow copy, and if B does not change, it is a deep copy. In depth, B copies A. if B copies the reference of a, it is a shallow copy. If B copies the ontology of a, it is a deep copy.
First, before we get to the point, we need to understand the stack and data types

Stack and data type

In JS, data types are divided into two types: basic type and reference type
Basic types: number, string, Boolean, null, undefined. Their values are saved in the stack in the form of key value pairs. (source network)

Reference type: object. Everything is an object. Using typeof to detect null also returns object. Different from the basic type, the value of the reference type is saved in the heap and the reference is saved in the stack (image source network)

Looking back at the first sentence, shallow copy is the reference of the copy object, so there is no deep and shallow copy of the basic data type. When a = 1 and B = a, a new memory will be opened up, as shown in the following figure (source network)

The root of deep copy and shallow copy lies in the reference type. When we define an array a=[0,1,2,3,4], b=a, we actually copy the reference address of a, not the value in the heap. Because a and b point to the same heap address, when we change a or b, the other will also change, which is shallow copy. (source network)

Many times we don't want a and b to interact with each other, so we need to make a deep copy. Let a and b specify different addresses, as shown in the figure below (source network)

Implement shallow copy

  1. The first way
    function simpleClone(initalObj) {
        var obj = {};
        for (let i in initalObj) {
            obj[i] = initalObj[i];
        }
        return obj;
    }
    var obj = {
        a: "hello",
        b: {
            a: "world",
            b: 21
        },
        c: ["Bob", "Tom", "Jenny"],
        d: function () {
            alert("hello world");
        }
    };
    
    var cloneObj = simpleClone(obj);
    
    //Change a, B, C and D in the original object to see if the copied object has changed
    cloneObj.a = "changed";
    cloneObj.b.a = "changed";
    cloneObj.b.b = 25;
    cloneObj.c = [1, 2, 3];
    cloneObj.d = function () {
        alert("changed");
    };
    console.log(obj.a);    //hello
    console.log(obj.b);    //{a:"changed",b:25}. In fact, only objects are copied reference types
    console.log(obj.c);    //['Bob','Tom','Jenny']
    console.log(obj.d);    //ƒ () {alert("hello world");}

It has been proved that the shallow copy only copies one layer. Except that the object is the reference of the copy, all others pass the value directly and have their own memory space. A shallow copy of the basic type is equal to a deep copy.

  1. The second way
    Use the object of ES6 Assign method, object Assign () can copy the enumerable attributes of any number of source objects (enumerable attributes refer to the attributes that can be traversed) to the target object, and then return to the target object
    Object.assign(target,... source) target: target object, source: multiple source objects
     let obj1 = {
        a: "hello",
        b: {
            a: "hello",
            b: 21}
    };

    let cloneObj1 = Object.assign({},obj1)
    console.log(cloneObj1.a)
    console.log(cloneObj1.b.a)

    //Change a and B in the original object to see if the copied object changes
    cloneObj1.a = 'changed'
    cloneObj1.b.a = 'changed'
    console.log(obj1.a)  //hello
    console.log(obj1.b.a)   //changed

Important: when the object has only one layer, it is a deep copy. Objects above the second level are shallow copies.

Enable deep copy

  1. JSON.parse(JSON.stringify())
    JSON.pase: convert string to object
    JSON.stringify: converts an object to a string
 let obj3 = {
        a: "hello",
        b:{
            a: "world",
            b: 21
        },
        c:["Bob", "Tom", "Jenny"]
    };

    let obj4 = JSON.parse(JSON.stringify(obj3))

    obj4.a = "changed";
    obj4.b.a = "changed";
    obj4.b.b = 25;
    obj4.c = [1, 2, 3];
    console.log(obj3.a)  //hello
    console.log(obj3.b.a)//world
    console.log(obj3.b.b)//21
    console.log(obj3.c)  //["Bob", "Tom", "Jenny"]

Important: you cannot clone functions in this way

  1. recursive copying
  function deepClone(obj) {
        if (obj instanceof Object) {   //When copying objects
            let tmp = {}
            for (let key in obj) {
                tmp[i] = deepClone(obj)
            }
            return tmp
        } else if (obj instanceof Array) {   //When copying an array
            let arr = []
            for (let i = 0; i < obj.length; i++) {
               arr.push(deepClone(obj[i]))
            }
            return arr
        }else if(obj instanceof Function){  //When copying functions
            return new Function('return' + obj.toString())
        }else{  //When the basic data type is copied
            return obj
        }
    }

Tags: Javascript

Posted by nicelad_uk on Fri, 13 May 2022 18:30:21 +0300