假设B复制了A 此时 B 和 A 的值相同, 但是当修改 A 的值,如果 B 的值随着 A 的值变化而变化 则说明是浅拷贝;如果 B 的值不随着 A 的变化而变化,则说明是深拷贝。
浅拷贝
简单的赋值 => 其实复制的是a的引用地址,而并非堆里面的值
let a = [0,1,2,3,4,5]
let b = a
console.log(a===b) //true
a[0]=1
console.log(a,b) //(6) [1, 1, 2, 3, 4, 5] (6) [1, 1, 2, 3, 4, 5]
当 b = a 赋值时,实际上是把 a 的引用地址赋给了 b ,而不是简单的值
将 a 比喻成是一个办公室 a 的内容是办公室里的每个人,内存比作整个办公室,a的引用地址就是每个人配套的办公桌。 当 b = a 时 实际上是将a的引用地址复制了过来 也就相当于将每个人及其办公桌复制过来了,当办公室有人员变动时,a的办公桌上的人由A 变成A1,由于b复制的是引用地址,所以b也从A变成了A1
深拷贝
一般需要递归实现 => 深拷贝,是拷贝对象各个层级的属性
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{}
if(obj && typeof obj === 'object'){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断obj子元素是否为对象,如果是,递归复制
if(obj[key] && typeof obj[key] === 'object'){
objClone[key] = deepClone(obj[key])
}else{
//如果不是 简单复制
objClone[key] = obj[key]
}
}
}
}
return objClone
}
let a = [1,2,3,4]
let b = deepClone(a)
a[0] = 9
console.log(a,b) // (4) [9, 2, 3, 4] (4) [1, 2, 3, 4]
ps: arr.slice() 方法和 arr.concat() 虽然看起来像深拷贝 但是不是深拷贝
let a=[0,1,[2,3],4],
b=a.slice();
console.log(a,b) // (4)[0,1,[2,3],4] (4)[0,1,[2,3],4]
a[0]=1;
console.log(a,b) // (4)[1,1,[2,3],4] (4)[0,1,[2,3],4]
a[2][0]=1;
console.log(a,b) // (4)[1,1,[1,3],4] (4)[0,1,[1,3],4]
//b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。
//第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题
除了递归还可以使用JSON对象的parse和stringify
function deepClone(obj){
let _obj = JSON.stringify(obj)
let objClone = JSON.parse(_obj)
return objClone
}
let a = [1,2,3,4]
let b = deepClone(a)
a[0] = 9
console.log(a,b) // (4) [9, 2, 3, 4] (4) [1, 2, 3, 4]