Differences and implementation of js shallow copy and deep copy

Posted by Ferenc on Tue, 18 Jan 2022 09:53:41 +0100

come from: https://www.jianshu.com/p/1c142ec2ca45 Invasion and deletion

 

How to distinguish between deep copy and shallow copy? To put it simply, assume that B copies A. when modifying a, see whether B will change. If B also changes, it means that this is a shallow copy. If B does not change, it is a deep copy and supports itself.

1. If it is a basic data type, the name and value will be stored in the stack memory

var a = 1;
b = a; // Stack memory will open up a new memory space. At this time, b and a are independent of each other
b = 2;
console.log(a); // 1

Of course, this is not a deep copy, because the deep copy itself is only for more complex object type data.

2. If it is a reference data type, the name is stored in the stack memory and the value is stored in the heap memory, but the stack memory will provide a reference address to point to the value in the heap memory

For example, shallow copy:
 
image.png

When b=a is copied, the reference address of a is copied instead of the value in the heap.


 
image.png

When we modify the array when a[0]=1, because a and b point to the same address, naturally b is also affected, which is the so-called shallow copy.


 
image.png

Then, if we open up a new memory in the heap memory to store values for b, just like the basic type, wouldn't it achieve the effect of deep copy
 
image.png

3. Method of realizing shallow copy

(1) for ··· in only circulates the first layer

// Copy only the shallow copy of the first layer
function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
   obj2[i] = obj1[i];
  }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
         d: 3
      }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4

(2)Object.assign method

var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3

(3) Direct use = assignment

let a=[0,1,2,3,4],
    b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
 
image.png

4. Method of realizing deep copy

(1) Use recursion to copy all hierarchical attributes

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //Judge whether the ojb child element is an object. If so, copy recursively
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //If not, simply copy
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);

result:


 
image.png

(2) Realize deep copy through JSON object

function deepClone2(obj) {
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
}

Disadvantages: unable to implement deep copy of methods in the object, and it will be displayed as undefined
(3) Deep copy is realized through the extend method of jQuery

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true is a deep copy and false is a shallow copy

(4) Implementation of deep copy with lodash function library

let result = _.cloneDeep(test)

(5) Reflect ion method

// Agency law
function deepClone(obj) {
    if (!isObject(obj)) {
        throw new Error('obj Not an object!')
    }

    let isArray = Array.isArray(obj)
    let cloneObj = isArray ? [...obj] : { ...obj }
    Reflect.ownKeys(cloneObj).forEach(key => {
        cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
    })

    return cloneObj
}

(6) Manual implementation of deep copy

let obj1 = {
   a: 1,
   b: 2
}
let obj2 = {
   a: obj1.a,
   b: obj1.b
}
obj2.a = 3;
alert(obj1.a); // 1
alert(obj2.a); // 3

(7) If the value of an object is a basic type, you can also use object Assign to implement the deep copy, but assign it to an empty object

var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign({}, obj); // obj is assigned to an empty {}
obj1.a = 3;
console.log(obj.a);// 1
 
image.png

(8) Deep copy of array with slice

// When the values in the array are basic data types, such as String, Number and Boolean, they belong to deep copy
// When the value in the Array is a reference data type, such as Object and Array, it belongs to shallow copy
var arr1 = ["1","2","3"]; 
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log("Original value of array:" + arr1 );
console.log("New value for array:" + arr2 );
 
image.png

(9) Deep copy of array with concat

// When the values in the array are basic data types, such as String, Number and Boolean, they belong to deep copy
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log("Original value of array:" + arr1 );
console.log("New value for array:" + arr2 );
// When the value in the Array is a reference data type, such as Object and Array, it belongs to shallow copy
var arr1 = [{a:1},{b:2},{c:3}];
var arr2 = arr1.concat();
arr2[0].a = "9";
console.log("Original value of array:" + arr1[0].a ); // Original value of array: 9
console.log("New value for array:" + arr2[0].a ); // New value of array: 9
 
image.png

(10) Directly use VaR newobj = object Create (oldobj) can achieve the effect of deep copy.

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // Avoid dead loops caused by cross referencing objects, such as initalobj A = case of initalobj
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

(11) Deep copy using extended operators

// When value is a basic data type, such as String, Number and Boolean, you can use the extension operator for deep copy
// When value is the value of reference type, such as Object and Array, deep copy of reference type only copies the reference address, so it belongs to shallow copy
var car = {brand: "BMW", price: "380000", length: "5 rice"}
var car1 = { ...car, price: "500000" }
console.log(car1); // {brand: "BMW", price: "500000", length: "5 m"}
console.log(car); // {brand: "BMW", price: "380000", length: "5 m"}