preface
Talking about deep copy again, it’s been two or three years! The flower has a day to open again, people no longer young ah, from the original ignorant to the present greasy uncle, harm
Base and reference types
Let’s start by explaining the difference between a primitive type and a reference type
Basic data types: Data stored directly in the stack
String, Number, Boolean, Null, Undefined, Symbol
let a = 1
let b = a
b = 2
console.log(a,b)
// 1 , 2
Copy the code
Variables A and B are both basic types. If we modify b directly, A will not be affected
Reference data types: Store references to the object in the stack, and the real data is stored in the heap.
Object 、Array 、Function 、Data
Come!!
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = {
name: 'Yim Ka-fai'.age: 18
}
console.log(obj === obj1)
Copy the code
Output what?
I’m sure some of you already know that false, but why is that? The truth is that the reference address is different because it’s a reference type, right
Variables of the reference type, == and ===, only determine whether the address of the reference is the same, but not whether the attributes and values of the object are the same
How do I compare whether an object is equal?
1.JSON.stringify
console.log(JSON.stringify(obj) === JSON.stringify(obj1))
// true
Copy the code
We are now converting obj to string, without comparing reference addresses
'{"name":" yj ","age":18}'= = ='{"age":18,"name":" yan Jia fai "}'
Copy the code
But there’s a problem with that
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = {
age: 18.name: 'Yim Ka-fai'
}
console.log(JSON.stringify(obj) === JSON.stringify(obj1))
Copy the code
After changing the order of obj1? Now are these two objects equal? It’s going to return false
So how do we determine whether two objects (kv of indefinite order) are equal?
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = {
age: 18.name: 'Yim Ka-fai'
}
const isSame = (obj1, obj2) = > {
var obj1keys = Object.keys(obj1);
var obj2keys = Object.keys(obj2);
if(obj2keys.length ! == obj1keys.length)return false
for (let i = 0; i <= obj1keys.length - 1; i++) {
let key = obj1keys[i]
if(! obj2keys.includes(key))return false
if(obj2[key] ! == obj1[key])return false
}
return true
}
console.log(isSame(obj,obj1)) // true
Copy the code
Objects whose values are basic data types can then be compared regardless of whether the order is consistent
About reference address
All right, let’s go back and look at this
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = obj
console.log(obj === obj1)
Copy the code
We said earlier that the ==, === of a reference type only determines whether its reference address is the same
Then its reference address here must be the same, so print true
So NOW I need to change the age of obj1 to 24
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = obj
obj1.age = 24
console.log('obj',obj)
console.log('obj1',obj1)
Copy the code
What does it output?
Why does OBJ change
When we assign these variables to another variable using =, we actually make a copy of the corresponding value and then assign the value to the new variable.
Objects are passed by reference, not by value. That is, variable assignments simply pass the address.
So when we modify obj1, we actually modify obj itself
So the question is, let’s say we have a requirement on the project
That is, the target object data. Function A is executed first, and then function B, but function B uses data.name as Yan Jiahui
let data = {
name: 'Yim Ka-fai'.age: 18
}
const a = () = > data.name = 'the old yan'
const b = () = > console.log('b',data.name) / / the old yan
a()
b()
Copy the code
This is where we need to look at deep copy
What is deep copy?
In the figure we can see that we have opened a new heap in memory to copy obJ’s data, but modifying obj1 does not affect OBj
Create a new object or array and copy the “values” (all the elements of the array) of the properties of the original object, which are “data” rather than “reference addresses”. We want to change the new object without affecting the original object
How do you do that?
1. JSON serialization
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
// Core content
let data1 = JSON.parse(JSON.stringify(data))
data1.name = 'the old yan'
data1.other.gender = 'woman'
console.log('a function',data1.name)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
The object is first converted to a string via json.stringify and then reserialized as an object.
This should be the simplest deep copy
The disadvantage is that functions are lost if the object contains them
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"
},
// add a test function
test: function() {}}const a = () = > {
let data1 = JSON.parse(JSON.stringify(data))
data1.name = 'the old yan'
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
Let’s see if the test is cold
2, for in
const deepCopy = obj= > {
// Check whether it is an array or an object
let result = typeof obj.splice === "function" ? [] : {};
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj[key] && typeof obj[key] === 'object') {
// deepClone is recursively called when the value of the object is object, that is, a copy of the value object into the corresponding value of the new object.
result[key] = deepCopy(obj[key]);
} else {
// If the attribute value of the object is not object, directly copy each key value of the parameter object into the corresponding key value pair of the new object.result[key] = obj[key]; }}// Returns the copied data
return result;
}
return obj;
}
/ / use
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
let data1 = deepCopy(data)
data1.name = Next door flower
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
Returns new data by traversing the data after a copy
Cons: It is said that if the data depth > 1000+ will burst the stack
3. Lodash library
Use the Lodash library for deep copy
html
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
Copy the code
js
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
// Core code
let data1 = _.cloneDeep(data)
data1.name = Next door flower
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
4, $. The extend
html
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
Copy the code
js
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
// Core code
let data1 = $.extend(true,{},data);
data1.name = Next door Lao Wang
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
The subtotal
The first or second option is recommended; the latter two require the introduction of external libraries
There are other ways to implement deep copy, such as Proxy, tree traversal, etc
What’s the shallow copy?
Everything has its opposite, its depth and its lightness
A deep copy is a copy of the “values” (all the elements in the array) of the original object. A shallow copy is a copy of the original object’s reference address
For shallow copies, only the reference to the object is copied, but the value of the object is not deeply copied. Multiple objects point to the same object in heap memory, and any modification causes all objects to change their value because they share a single data
Find the previous example and diagram, which is a typical shallow copy
let obj = {
name: 'Yim Ka-fai'.age: 18
}
let obj1 = obj
obj1.age = 24
Copy the code
Does that make sense?
What? I don’t know. Let’s write two more chestnuts
Shallow copy implementation
1, for the in
const deepCopy = obj= > {
let result = typeof obj.splice === "function" ? [] : {};
if (obj && typeof obj === 'object') {
for (let key in obj) {
// Drop the recursion and let the second level data be assigned directly (reference address)
result[key] = obj[key];
}
return result;
}
return obj;
}
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
let data1 = deepCopy(data);
data1.name = Next door Lao Wang
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
We directly use the second implementation of deep copy to remove the recursion and let it directly assign (reference addresses), which implements a shallow copy
2, the Object. The assign
let data = {
name: 'Yim Ka-fai'.age: 18.other: {
gender: "Male"}}const a = () = > {
// Core code
let data1 = Object.assign({},data);
data1.name = 'Flowers in a village in a city'
data1.other.gender = 'woman'
console.log('a function',data1)
}
const b = () = > console.log('b',data) / / the old yan
a()
b()
Copy the code
The subtotal
It is true that the first layer of data is copied successfully, but we still copy the reference address when the object’s property is reference type data
conclusion
The difference between deep and shallow copy is that the former copies the original data and creates a new address, while the latter copies the reference address of the original data
If there are mistakes, please kindly comment.
Reference documentation
www.jianshu.com/p/f4329eb1b…
Segmentfault.com/a/119000001…