Deep copy and shallow copy

Keywords: Javascript ECMAScript html5 html

1. What is shallow copy

Create a new object that has an exact copy of the original object property values. If the attribute is a basic type, the value of the basic type is copied. If the attribute is a reference type, the memory address is copied  , So if one object changes this address, it will affect the other object.

Above, ` SourceObject`   Is the original object, which contains basic type properties  ` field1`   And reference type properties  ` refObj`. Basic type data after shallow copy  ` field2`   and  ` filed1`   They are different attributes and do not affect each other. But the reference type  ` refObj`   It is still the same, and the change will have an impact on another object.

In short, it can be understood that shallow copy only solves the problem of the first layer, copying the * * basic type value * * of the first layer and the * * reference type address * * of the first layer.

2. Shallow copy usage scenario

2.1 Object.assign()

`Object.assign()`   Method is used to copy the values of all enumerable properties from one or more source objects to the target object. It will return the target object.

Some articles say ` Object.assign()`   It's a deep copy. In fact, this is not correct.

// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don't Know JS",
        price: "45"
    }
}
let b = Object.assign({}, a);
console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
// 	name: "change",
// 	book: {title: "You Don't Know JS", price: "55"}
// } 

console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "55"}
// }

The above code changes the object   a   After that, the object   b   The basic properties of remain unchanged. But when changing objects   a   Objects in  ` book`   Object when   b   The corresponding position has also changed.

2.2 expand syntax  ` Spread`

// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don't Know JS",
        price: "45"
    }
}
let b = {...a};
console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
// 	name: "change",
// 	book: {title: "You Don't Know JS", price: "55"}
// } 

console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "55"}
// }

2.3 Array.prototype.slice method

Slice does not change the original array, ` slice()`   Method returns a new array object, which is a  ` begin ` and  ` End ` (excluding ` end `) determines the * * shallow copy * * of the original array.

// saucxs
let a = [0, "1", [2, 3]];
let b = a.slice(1);
console.log(b);
// ["1", [2, 3]]

a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]

console.log(b);
//  ["1", [4, 3]]

As can be seen, change  ` a[1]`   after  ` b[0]`   The value of did not change, but changed  ` a[2][0]`   After that, the corresponding  ` b[1][0]`   The value of also changes.

explain  ` slice()`   The method is shallow copy, and the corresponding 'concat' should pay extra attention to the complex array structure in the work.

3, Deep Copy

3.1 what is deep copy?

Deep copy copies all attributes and dynamically allocated memory pointed to by attributes. A deep copy occurs when an object is copied with the object it references. Deep copy is slower and more expensive than shallow copy. The two objects do not affect each other before and after copying.

3.2 scenario of using deep copy

3.2.1 JSON.parse(JSON.stringify(object))

// saucxs
let a = {
    name: "saucxs",
    book: {
        title: "You Don't Know JS",
        price: "45"
    }
}
let b = JSON.parse(JSON.stringify(a));
console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "45"}
// } 

a.name = "change";
a.book.price = "55";
console.log(a);
// {
// 	name: "change",
// 	book: {title: "You Don't Know JS", price: "55"}
// } 

console.log(b);
// {
// 	name: "saucxs",
// 	book: {title: "You Don't Know JS", price: "45"}
// }

Completely change variables   a   Later on   b   Without any effect, this is the magic of deep copy.

Let's see how the deep copy of the array works.

// saucxs
let a = [0, "1", [2, 3]];
let b = JSON.parse(JSON.stringify( a.slice(1) ));
console.log(b);
// ["1", [2, 3]]

a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]

console.log(b);
//  ["1", [2, 3]]

After deep copying the array, changing the original array will not affect the copied array.

However, this method has the following problems:

(1) Will ignore  ` undefined`

(2) Will ignore  ` symbol`

(3) Cannot serialize function

(4) Circular referenced objects cannot be resolved

(5) Cannot process ` new correctly   Date()`

(6) Cannot handle regular

Where (1) (2) (3) ` undefined ', ` symbol'`   And functions are ignored directly.

// saucxs
let obj = {
    name: 'saucxs',
    a: undefined,
    b: Symbol('saucxs'),
    c: function() {}
}
console.log(obj);
// {
// 	name: "saucxs", 
// 	a: undefined, 
//  b: Symbol(saucxs), 
//  c: ƒ ()
// }

let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "saucxs"}

Among them, (4) circular reference will report an error

// saucxs
let obj = {
    a: 1,
    b: {
        c: 2,
   		d: 3
    }
}
obj.a = obj.b;
obj.b.c = obj.a;

let b = JSON.parse(JSON.stringify(obj));
// Uncaught TypeError: Converting circular structure to JSON

Including (5)*  ` new   Date`   In this case, the conversion result is incorrect.

// saucxs
new Date();
// Mon Dec 24 2018 10:59:14 GMT+0800 (China Standard Time)

JSON.stringify(new Date());
// ""2018-12-24T02:59:25.776Z""

JSON.parse(JSON.stringify(new Date()));
// "2018-12-24T02:59:41.523Z"

The solution is to convert it into a string or timestamp.

// saucxs
let date = (new Date()).valueOf();
// 1545620645915

JSON.stringify(date);
// "1545620673267"

JSON.parse(JSON.stringify(date));
// 1545620658688

Where (6) regular case

// saucxs
let obj = {
    name: "saucxs",
    a: /'123'/
}
console.log(obj);
// {name: "saucxs", a: /'123'/}

let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "saucxs", a: {}}

PS: why do these problems exist? You can learn from them   JSON.

In addition to the deep copy method described above,

Also commonly used is ` jQuery.extend()`   and  ` lodash.cloneDeep() `. The following article will introduce the source code implementation in detail.

4, Summary

  Whether the data and the original data point to the same object  The first layer of data is the basic data type  The original data contains child objects
  assignmentyes    Change will change the original data together  Change will change the original data together
  Shallow copyno    Change will not change the original data together  Change will change the original data together
  Deep copyno    Change will not change the original data together  Change will not change the original data together

Posted by pureDesi on Tue, 12 Oct 2021 19:16:12 -0700