Shallow copy and deep copy in the front end

Not much to say, first let's take a look at the following code:

let obj = {
    
     num: 1 }
console.log(obj.num)
// 1
let copy = obj
copy.num = 2
console.log(obj.num)
// 2
console.log(obj === copy) // true 完全相等的两个对象

From the code, we can clearly see that the value of obj.num has changed, but on the surface, we don’t seem to be operating on obj . Why does this phenomenon occur? This is what is called a shallow copy .

Understanding shallow copy and deep copy

First understand the reference type. The storage address of the reference type is the address where its real data is stored .

To put it another way: for example, when we go to pick up the courier, if the variable is a basic type, then we go directly to the address it gave us to get it, but if it is a reference type, we go to the address given by him I got a small piece of paper, which stated the real location of our courier. Only by going to the address on the piece of paper can we successfully pick up our courier.

Since the object type (object, array...) is a reference type, its storage in memory stores its reference address (the address of the real storage location of the data). When we do a shallow copy operation, we actually copy this reference The address is assigned to another variable, so in the end they both get the same object (equivalent to copying just the little note). And deep copy is to open up another location in memory to store another object, but this object is consistent with the data of the object we copied.

Common ways to implement shallow copy

Method 1: Implemented through the spread operator

The method of the spread operator can not only shallow copy the array (example above), but also shallow copy the object. Here we give another example of shallow copy object:

let obj = {
    
    a:1,b:2,c:{
    
    d:3,e:[1,2]}}

let obj1 = {
    
    ...obj}

// 通过扩展运算符浅拷贝,获得对象obj1

console.log(obj === obj1)

// false,obj和obj1分别指向不同的对象

console.log(obj.c === obj1.c)

// true,但是obj的c属性的值和obj1的c属性的值是同一个内存地址

方法2:通过Object.assign方法实现

Object.assign()方法只适用于对象,可以实现对象的合并,语法:

Object.assign(target, source_1, ..., source_n).

The Object.assign() method will copy the enumerable properties in the source to the target, and copy the property value. If the property value is a reference type, then copy the reference address, so it is also a shallow copy. Examples are as follows:

let target= {
    
    

name: "小明",

}

let obj1 = {
    
    

age: 28,

sex: "男",

}

let obj2 = {
    
    

friends: ['朋友1','朋友2','朋友3'],

sayHi: function (){
    
    

console.log( 'hi' )

},

}

let obj = Object.assign(target,obj1,obj2)

console.log(obj === target) // true,因此可以用变量接收结果,也可以直接使用target

obj1.age = 30 // 把obj1的age属性值改成30

console.log("target",target)

console.log("obj1",obj1)

We can see that the returned results obj and target both point to the new object of the shallow copy, and modifying the attribute age of obj1 will not affect the age attribute value of target.

At this point, add a new friend 4 to the friends attribute of the target, the operation is as follows:

target.friends.push("Friends 4")

console.log(“target”,target)

console.log(“obj2”,obj2)

At this time, the values ​​of the friends attribute of target and the friends attribute of obj2 point to the same array.

Common methods for implementing deep copy

Method 1: Implemented by recursively copying all levels

Here we implement a deep copy by encapsulating a deepClone function, which is applicable to objects or arrays. The code is as follows:

let obj = {
    
    

name: '小明',

age: 20,

arr: [1, 2],

}

function deepClone(value) {
    
    

// 判断传入参数不是对象或数组时直接返回传入的值,不再执行函数

if (typeof value !== 'object' || value == null) {
    
    

return value

}

//定义函数的返回值

let result

// 判断传进来的数据类型数组还是对象,对应创建新的空数组或对象

if (value instanceof Array) {
    
    

result = []

} else {
    
    

result = {
    
    }

}

// 循环遍历拷贝

for (let key in value) {
    
    

//函数递归实现深层拷贝

result[key] = deepClone(value[key])

}

// 将拷贝的结果返回出去

return result

}

let newObj = deepClone(obj)

obj.arr[0] = 0 // 修改原对象的arr属性对应的数组的元素值

console.log("obj",obj)

console.log("newObj ",newObj )

The following is the print result of the above code:

We can see that the deep recursion method will not copy the reference address, so modifying the elements of the array corresponding to the arr attribute of the original object obj will not affect the new object newObj.

Method 2: Implemented through the stringify and parse methods of the JSON object

When we explained the concept of deep copy above, we used this method to deep copy arrays. Here we give an example of deep copy objects:

let obj = {
    
    

name: '小明',

age: 20,

arr: [1, 2],

}

let obj1= JSON.parse( JSON.stringify(obj) )

console.log(obj.arr === obj1.arr)

// false,此时obj的arr属性和obj1的arr属性值不是同一个数组

Through the code, we can find that the JSON.stringify() method will convert obj into a string first, and the string does not represent any space address, it is a simple string, and the JSON.parse() method parses the string into For new objects, each level of the object will open up new space in the heap memory.

Summarize

The shallow copy and deep copy of JS are mainly used in multi-level arrays or objects. Shallow copy is to copy only the first layer of the created array or object, and other layers have the same address value as the original array or object, so modifying the value of the deep layer of the shallow copied array or object will affect the value of the original array or object. The deep copy is to copy a brand new array or object, each level opens up a new space in the heap memory, and does not affect each other with the original array or object.

Guess you like

Origin blog.csdn.net/huangzhixin1996/article/details/132013482