深拷贝浅拷贝的区别?如何实现一个深拷贝?
一、数据类型存储
JavaScript中存在两大数据类型:
- 基本类型 Number String null Undefined Boolean
- 引用类型 array object function
基本类型数据保存在在栈内存中
引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中
二、浅拷贝
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
/*
1.浅拷贝 与 深拷贝
浅拷贝: 拷贝地址, 修改拷贝后的数据对原数据有影响
深拷贝: 拷贝数据, 修改拷贝后的数据对原数据没有影响
2.深拷贝实现方式
2.1 使用JSON : let newObj = JSON.parse( JSON.stringify( obj ) )
2.2 使用递归 :
*/
let obj = {
name:'张三',
age:20,
hobby:['学习','上课','干饭']
}
//1.浅拷贝 : 拷贝地址
// let newObj = obj
// newObj.name = '李四'
// newObj.hobby[0] = '游戏'
// console.log(obj,newObj)//修改newObj, obj也会修改
//2.使用JSON
//(1)把obj转成json格式字符串 : 底层会自动深拷贝
// let jsonStr = JSON.stringify( obj )
// console.log(jsonStr)
//(2)把json转成对象
// let newObj = JSON.parse( jsonStr )
let newObj = JSON.parse( JSON.stringify( obj ) )
newObj.name = '李四'
newObj.hobby[0] = '游戏'
console.log(obj,newObj)
}
三、深拷贝
深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
- JSON.stringify()
- 手写循环递归
1.递归函数: 一个函数 在内部 调用自己
* 递归作用和循环类似的,也需要有结束条件
2.递归应用:
浅拷贝与深拷贝 :
方式一(推荐) : JSON方式实现
* let newObj = JSON.parse( JSON.stringify( obj ) )
方式二(递归) : 了解
遍历dom树
*/
let obj = {
name: '张三',
age: 20,
sex: '男',
hobby: ['吃饭', '睡觉', '学习'],
student: {
name: "班长",
score: 90
}
}
//使用递归函数
function kaobei(obj, newObj) {
for (let key in obj) {
if (obj[key] instanceof Array) {
//声明一个空数组,然后继续拷贝数组里面的数据
newObj[key] = []
//递归调用继续拷贝 数组
kaobei(obj[key], newObj[key])
} else if (obj[key] instanceof Object) {
//声明一个空对象
newObj[key] = {}
//递归调用继续拷贝 对象
kaobei(obj[key], newObj[key])
} else {
newObj[key] = obj[key]
}
}
}
//创建一个空对象,然后深拷贝
let newObj = {}
kaobei(obj, newObj)
newObj.name = '李四'
newObj.hobby[0] = '摸鱼'
newObj.student.name = 'ikun'
console.log(obj, newObj)
JSON.stringify()
const obj2=JSON.parse(JSON.stringify(obj1));
但是这种方式存在弊端,会忽略undefined和函数
四、区别
从上图发现,浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样
浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象
小结
前提为拷贝类型为引用类型的情况下:
- 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
- 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
总结:
- 深拷贝递归地复制新对象中的所有值或属性,而拷贝只复制引用。
- 在深拷贝中,新对象中的更改不会影响原始对象,而在浅拷贝中,新对象中的更改,原始对象中也会跟着改。
- 在深拷贝中,原始对象不与新对象共享相同的属性,而在浅拷贝中,它们具有相同的属性。