Deep and shallow copies

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.

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
a = 3
console.log(b); // 2

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

var a = [1]
var b = a // Shallow copy
var c = [...a] // Deep copy
a.push(2)
console.log(b); // [1,2]
console.log(c); // [1]
b.push(3)
console.log(a) // [1,2,3]

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:

Shallow copy: when b=a is copied, the reference address of a is copied instead of the value in the heap:

When we modify the array when a[0]=1, because a and b point to the same address, naturally b is also affected:

In order to realize deep copy, a new memory should be opened in the heap memory to store values for b, just like the basic type:

Why [] = = [] is false: each time [] is used, a new array object is created. When arrays are compared, their references are actually compared. [] = = [] Although both sides are [], both sides are not equal in terms of reference.

Method for realizing shallow copy

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

function simpleCopy(obj1) {
  var obj2 = {}
  for (let i in obj1) {
    obj2[i] = obj1[i];
  }
  return obj2;
}
var obj1 = {
  a: 1,
  c: {
    d: 3
  }
}
var obj2 = simpleCopy(obj1);
obj2.a = 11;
obj2.c.d = 33;
console.log(obj1.a); // 1
console.log(obj2.a); // 11
console.log(obj1.c.d); // 33
console.log(obj2.c.d); // 33

(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

var a = [0,2,3];
var b = a;
a[0] = 1;
console.log(a) // [1,2,3]
console.log(b) // [1,2,3]

Method for 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); // [ 2, 2, 3, 4 ]
console.log(b);  // [ 1, 2, 3, 4 ]

(2) Realize deep copy through JSON object

function deepClone2(obj) {
  var _obj = JSON.stringify(obj) // The JSON.stringify() method is used to convert JavaScript values to JSON strings.
  var objClone = JSON.parse(_obj) // Use the JSON.parse() method to convert the data into JavaScript objects
  return objClone;
}
var o1 = {
  a: 1,
  b: {
    c: 2
  },
  f: function () {
    console.log(1)
  }
}
var o2 = deepClone2(o1)
o1.a = 11
o1.b.c = 22
console.log(o1); // { a: 11, b: { c: 22 }, f: [Function: f] }
console.log(o2); // { a: 1, b: { c: 2 } }

Disadvantages: unable to implement the deep copy of the method in the object, and it will be displayed as undefined

(3) Implementation of deep copy with lodash function library

let b = _.cloneDeep(a)

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

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

(5) Deep copy of array with slice

Note: 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] = 0;
console.log(arr1); // [1,2,3]
console.log(arr2); // [1,0,3]

(6) 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 (the same as slice)
var arr1 = [1, 2, 3];
var arr2 = arr1.concat();
arr2[1] = 0;
console.log(arr1); // [1,2,3]
console.log(arr2); // [1,0,3]
// 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 }];
var arr2 = arr1.concat();
arr2[0].a = 2
console.log(arr1[0].a); // 2
console.log(arr2[0].a); // 2

(7) Deep copy using extended operators
Similarly, it is similar to slice and concat:
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 a value of reference type, such as Object and Array, only the reference address is copied, so it belongs to shallow copy.

var o1 = {
  a: 1,
  b: {
    c: 2
  }
}
var o2 = { ...o1 }
o1.a = 11
o1.b.c = 22
console.log(o2.a); // 1
console.log(o2.b.c); // 22

Tags: Javascript

Posted on Mon, 06 Sep 2021 20:34:31 -0400 by rallokkcaz