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.