带你搞懂js的深拷贝
js深拷贝
在讲正题之前我们要先了解数据存储的方式
数据存储方式
在讲之前我们要先知道值类型和引用类型的存储方式。
在JavaScript数据类型中有两种数据类型。
值类型:字符串(String
)、数字 (Number
)、布尔 (Boolean
)、空(Null
)、未定义(Undefined
)、Symbol
。
存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。
引用数据类型:对象 (Object
) 、数组 (Array
) 、函数 (Function
) 。
存放在堆内存中的对象,在栈内存中存的是一个指针,这个指针指向堆内存一个位置。再从堆内存中取得所需的数据。
存储如下图:
什么是浅/深拷贝
讲完存储的方式,我们来讲讲浅拷贝和深拷贝
拷贝也就是我们常常讲的copy,ctrl+c,ctrl+v,那么我们来看看例子
当我们对分别值类型和引用类型进行赋值。
1
2
3
4
5
6
7
8
9
|
var a = 5
var b = a
b += 5
console.log( 'a=' + a, 'b=' + b)
var arr=[1,2,3]
var brr=arr
brr.push(10)
console.log( "arr为" ,arr)
console.log( "brr为" ,brr)
|
现象:我们发现值类型并没有互相受到影响,然而数组(引用类型)brr数组添加元素的时候改变了arr数组。
解释分析:浅拷贝只会发生在引用类型身上,对于引用类型如果之进行简单的赋值,只会赋值指向堆内存的指针,这种称为浅拷贝。而深拷贝就是完全拷贝一个引用类型,为不是地址指针。
浅拷贝看下面这张原理图:
常用深拷贝实现
那么我们在赋值引用类型的时候肯定不能出现浅拷贝的现象,对原数据产生影响了。那么就要进行深拷贝
1.通过JSON.stringify和JSON.parse
可以深拷贝的数组和对象,但是不能拷贝函数,可以进行对象或者数组的嵌套拷贝。
缺点:无法实现对对象中方法的深拷贝
使用:
1
|
var brr=JSON.parse(JSON.stringify(arr))
|
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var arr = {
name: '浪漫主义码农' ,
age: 20,
adress: [ 'jiangxi' , 'changsha' ],
friends: {
friend1: '张三' ,
friend2: '李四'
},
function (){
console.log( "我是浪漫主义的对象" )
}
}
var brr=JSON.parse(JSON.stringify(arr))
brr.name= '法外狂徒张三'
brr.adress[0]= '长沙'
console.log( "arr为" , arr)
console.log( "brr为" , brr)
|
2.扩展运算符
利用了对象的结构赋值特性方法。
缺点:无对对象里面嵌套的对象进行深拷贝,相当于只是对一层引用对象进行深拷贝
使用:
1
|
var brr={...arr}
|
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var arr = {
name: '浪漫主义码农' ,
age: 20,
adress: [ 'jiangxi' , 'changsha' ],
friends: {
friend1: '张三' ,
friend2: '李四'
},
function (){
console.log( "我是浪漫主义的对象" )
}
}
var brr={...arr}
brr.name= '法外狂徒张三'
brr.adress[0]= '长沙'
console.log( "arr为" , arr)
console.log( "brr为" , brr)
|
3.手写递归深拷贝函数
完美解决
函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//使用递归实现深拷贝
function deepClone(obj) {
//判断拷贝的obj是对象还是数组
var objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object" ) { //obj不能为空,并且是对象或者是数组 因为null也是object
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object" ) { //obj里面属性值不为空并且还是对象,进行深度拷贝
objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
} else {
objClone[key] = obj[key]; //直接拷贝
}
}
}
}
return objClone;
}
|
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
var arr = {
name: '浪漫主义码农' ,
age: 20,
adress: [ 'jiangxi' , 'changsha' ],
friends: {
friend1: '张三' ,
friend2: '李四'
},
fun: function (){
console.log( "我是" + this .name + "的对象" )
}
}
var brr = deepClone(arr)
brr.name = '法外狂徒张三'
brr.adress[0] = '长沙'
console.log( "arr为" , arr)
arr.fun()
console.log( "brr为" , brr)
brr.fun()
//使用递归实现深拷贝
function deepClone(obj) {
//判断拷贝的obj是对象还是数组
var objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object" ) { //obj不能为空,并且是对象或者是数组 因为null也是object
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object" ) { //obj里面属性值不为空并且还是对象,进行深度拷贝
objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
} else {
objClone[key] = obj[key]; //直接拷贝
}
}
}
}
return objClone;
}
|
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!