How do you distinguish between A deep copy and A shallow copy? In simple terms, suppose B copies A, and when YOU modify A, does B change? If B also changes, it is A shallow copy, and if B does not change, it is A deep copy

Let’s take a shallow copy example:

      let a = [0, 1, 2, 3, 4],
        b = a;
      console.log(a === b);
      a[0] = 1;
      console.log(a, b);
Copy the code

Huh? Why change array A when b copies array A?

Here, then, comes the concept of primitive and reference data types.

Basic data types,number, String, Boolean, NULL, undefined, symbol, and BigInt(arbitrary precision integer) classes added in ES10. Reference data types (Object classes) unordered objects {a:1}, arrays [1,2,3], functions, etc.

And these two types of data storage patterns look like this.

Basic data types

Name values are stored in stack memory, for example let a=1;

When you performb=aAfter that, a new stack memory is created, for example:

So one change doesn’t affect the other. The reference type is different.

Reference types

Reference datatype – the name is in stack memory, the value is in heap memory, but the stack memory provides a reference address to the value in heap memory.

When we let a=[1,2,3,4], we will:

When b=a is copied, it is actually copying the reference address of A, not the value in the heap.

When a[0]=6, we modify the array, because a and B point to the same address, so naturally B is affected, this is called shallow copy.



So what if our b points to a separate heap memory? It’s just the same with Val. As shown in the following figure, the effect of deep copy is achieved

Having said that, let’s talk about the implementation method!

Methods a

JSON.parse(JSON.stringify)

Const obj = {num: 3, STR: ", boy: {height: 21, weight: 105,}, arr: [1, 2, 3], fn: function () { console.log(2333); }, reg: /"/g, date: new Date(), }; const deep = JSON.parse(JSON.stringify(obj)); deep.boy.height = 30; console.log(obj); console.log(deep); //fn does not have reg as object and date as stringCopy the code

We find that the Date and RegExp types are {}, and my functions are gone.

Method 2

Through recursive implementation, determine whether it is the type of attribute object. If it is, recursively clone the value of the attribute. If it is a basic type, directly assign the value

Const obj = {num: 3, STR: ", boy: {height: 21, weight: 105,}, arr: [1, 2, 3], fn: function () { console.log(2333); }, reg: /"/g, date: new Date(), }; function deepClone(obj) { let objClone = Array.isArray(obj) 1 [] : {}; If (obj && typeof obj === "object") {// For (let key in obj) {// If (obj[key]) {// If (obj[key]) {// If (obj[key]); && typeof obj[key] === "object") { newObj[i] = Object.prototype.toString.call(oldObj[i]) === "[object Array]" ? [] : {}; deepClone(newObj[i], oldObj[i]); } else {// If not, simply clone objClone[key] = obj[key]; } } } return objClone; } const obj2 = deepClone(obj); console.log(obj2);Copy the code

As you can see from the diagram above, the RegExp and Date types are still the same result, so we need to create the same type space for both of them.

Methods three

Loop recursion, determine the type declaration corresponding to the type to copy.

Const obj = {num: 3, STR: ", boy: {height: 21, weight: 105,}, arr: [1, 2, 3], fn: function () { console.log(2333); }, reg: /"/g, date: new Date(), }; const obj2 = {}; deepClone(obj2, obj); obj.arr.push("4"); console.log(obj); console.log(obj2); obj2.fn(); Function deepClone(newObj, function deepClone(newObj, If (oldObj) {for (let I in oldObj) {if (oldObj[I] instanceof Date) {newObj[I] = new Date(oldObj[i]); } else if (oldObj[i] instanceof RegExp) { newObj[i] = new RegExp(oldObj[i]); } else if (typeof oldObj[i] === "object") { newObj[i] = Object.prototype.toString.call(oldObj[i]) === "[object Array]" ?  [] : {}; deepClone(newObj[i], oldObj[i]); } else { newObj[i] = oldObj[i]; }}}}Copy the code

The running results are as follows:

This is ok!

supplement

There are ways to implement shallow copying of the first layer

slice()||slice(0)

      const array = [1, 2, 3, 4, { a: 5 }];
      const obj2 = array.slice();
      array[0] = "aaa";
      array[4].a = 7;
      console.log(array, obj2);
Copy the code

As you can see on the way,obj2 does not change when you change the first layer, but changes when you change the second or deeper layer.

Extended operators…

      const array = [1, 2, 3, 4, { a: 5 }];
      const newArray = [...array];

      array[0] = "aaa";
      array[4].a = "aaaa";
      console.log(array, newArray);
Copy the code

Same as the picture above.