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…