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 | |
assignment | yes | Change will change the original data together | Change will change the original data together |
Shallow copy | no | Change will not change the original data together | Change will change the original data together |
Deep copy | no | Change will not change the original data together | Change will not change the original data together |