这是一个非常简易的深拷贝解析
<script>
//先设置一个对象,用来做拷贝
let obj = {
name: 'slimShady',
age: 45,
hobby: [
'rap--说唱',
'Political preaching--政治宣讲',
'Attack social phenomena--攻击社会现象'
],
class: {
name: 'personal rap class',
income: ['$20,000', '$25,000', '$30,000']
}
}
</script>
首先了解一下浅拷贝:
//浅拷贝 ,拷贝的是地址
let obj1 = obj //将obj在堆内存中的地址拷贝出来,复制给在栈内存中的obj1
obj1.name = '5cent' //更改obj1.name后,obj.name也会跟着改变
console.log(obj.name, obj1.name) // '5cent' '5cent'
console.log(obj === obj1) //true,此时obj与obj1不仅数据相同,地址也相同,所以输出为true
再来看看深拷贝: 深拷贝简单讲就是只拷贝数据,而不拷贝内存,
在实际开发中实现深拷贝有两种方式
1.简单方式:(实际开发中常用的方式):只需要把js对象先转成JSON,然后再转成js,就可以实现深拷贝。(这种方式会有一些弊端,简单说就是JSON只能遍历对象所有可枚举的属性,而其他的比如对象内的值为构造函数的实例对象或者比如NAN ,INFINITY ,-INFINITY这些属性时会造成数据丢失等等情况,这里不多做赘述)
//初始形态:
let json = JSON.stringify(obj)//编译器底层会自动深拷贝
console.log(json)
let js = JSON.parse(json)//将JSON对象再转换成js格式就可以实现深拷贝
console.log(js)
console.log(json === js)//false,此时json与js数据虽然相同但是地址不同,所以输出为false
// 简化形态:
let obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj2)
console.log(obj === obj2)
2.复杂数据:使用递归实现深拷贝:
2.1 不使用递归时,如果原对象都是简单数据类型,简单思路,遍历原对象,进行赋值:
function copyRight (newObj, obj) {
// 先遍历一遍原对象obj的每一个成员,赋值给newObj
for (let key in obj) {
newObj[key] = obj[key]
}
}
//然后声明一个新对象存储拷贝后的数据
let newObj = {}
//开始深拷贝
copyRight(newObj, obj)
console.log(newObj, obj)
//此时完成了非引用类型数据的深拷贝,但是引用类型数据并未深拷贝 */
2.2 使用递归,可以对对象中的引用数据类型进行遍历拷贝:深层深拷贝
//遍历原对象,但是针对不同数据类型做不同判断,如数组以及对象类型,先创建新容器,后进行赋值,而值类型数据则作为递归结束条件,实例如下:
function copyRight (newObj, obj) {
for (let key in obj) {
if (obj[key] instanceof Array) {
newObj[key] = []
copyRight(newObj[key], obj[key]) **==>在这里递归**
//数组:引用类型
// instanceof运算符的作用是用来检测constructor.prototype是否存在于参数object上
// 即检测某一数据类型的原型是否存在某一数据的原型链上,以此可以判断此数据为那种类型
// 此时为判断该obj[key]的原型链上是否存在Array数组的原型链,如果有则为数组,对象及值类型同理
} else if (obj[key] instanceof Object) {
//对象:引用类型
newObj[key] = {}
copyRight(newObj[key], obj[key]) **==>在这里递归**
} else {
newObj[key] = obj[key]
//数值类型终止递归
}
}
}
let newObj = {} //声明一个空对象存储拷贝后的数据
copyRight(newObj, obj) //开始深拷贝
console.log(newObj, obj) //拷贝完成后newObj与obj数据相同但是地址不同
console.log(newObj === obj) //false//验证正确
</script>
一个非常简单的深拷贝完成。