在理解深拷贝和浅拷贝之前,咋们先了解下JavaScript有那些类型:
基本数据类型:Number、String、Boolean、undefined、Null、以及Es6新特性Symbol、或者未来Es10中的Bigint,一共是7种。
引用数据类型:Object,又细分为Object、Array、function等等
简单来讲,一共是8种数据类型;
接下来我们讲讲基本和引用数据类型的存储原理:
基本数据类型:存储方法是直接将数据存储在栈中。 引用数据类型:存储方式是先在栈中开辟一个空间也就是咋们常说的入栈,存入一个地址,然后这个地址是指向堆中的某个位置,数据实际是存放在堆中。
造成这种情况的原因是因为在赋值的过程中,仅仅是将栈中的地址进行了赋值,并没有在堆中给newobj重新开辟一个新的空间。导致obj和newobj指向同一个地址,这才是导致问题的所在。所以就导致了现在的很明显的旧数组修改了里面的某个字段,新的数组也跟着变了,这明显是不合理的。
浅拷贝代码如下
function shallowClone(obj){
let res = {}
for(let i in obj){
res[i] = obj[i]
}
return res
}
这是不符合我们的要求的,进入深拷贝实战
1,烂大街的乞丐版
function normalVersion(obj){
return JSON.parse(JSON.stringify(obj))
}
存在两个问题:存在函数无法复制 和循环引用问题 比如原对象有字段是函数就无法复制过去,循环引用就是对象中两个字段互相调用,你中有我,我中有你就爆炸了
2,深拷贝普通版 还是存在循环引用问题
function deepClone(obj){
let res = null
if(typeof obj ==='object'){
res = (obj instanceof Array) ? []: {}
for(let i in obj){
res[i] = typeof obj[i] ==='object'? deepClone(obj[i]) : obj[i]
}
}else{
res = obj
}
return res
}
3,深拷贝加强版 解决循环引用问题
//深拷贝加强版 解决循环引用问题
function deepCloneVersion2(obj,map=new Map()){
let res = null
if(typeof obj ==='object'){
//克隆之前进行判断数据之前是否克隆过
let cache = map.get(obj)
if(cache){
return cache
}
res = (obj instanceof Array) ? []: {}
map.set(obj,res)
for(let i in obj){
res[i] = typeof obj[i] ==='object'? deepCloneVersion2(obj[i],map) : obj[i]
}
}else{
res = obj
}
return res
}
调用例子
a:'a',
b:{
c:'c',
d:{
e:'e',
f:['f']
}
},
h:[1,2,3],
g:function(){}
}
source.h.push(source.b)
source.b.new = source.h
let target = deepCloneVersion2(source)
console.log('target',target)
console.log('source',source)