面试开发都会遇到的问题。咱就做个笔记记一下吧,嘿嘿。
浅拷贝
先看代码和打印结果
let aaa = {a:1,b:2};
let bbb = aaa;
console.log(aaa===bbb)
bbb.b = 3;
console.log(aaa)
console.log(bbb)
打印结果
可以看出来,当我们改变bbb.b的值,aaa.b的值也发生了改变。这是为什么呢?因为当我们进行赋值操作时,只是将aaa在栈中存放的数据地址给复制了过来,所以aaa和bbb其实是指向的堆中的同一个对象。
当aaa和bbb两者任一发生了改变,两者都会发生变化。
深拷贝
来,上代码
let obj = {
a: '1',
b: 666,
c: [
{ca1: 666,ca2: '999'},
{cb1: ['a', 1, 'b', 2],cb2: [{cba1: '999',cba2: 666}]},
[1, 2, 3]
]
}
function deepCopy(obj) {
let result = Array.isArray(obj) ? [] : {}; //判断拷贝对象数据类型为Object还是Array
for (item in obj) {
if (typeof obj[item] === 'object') { //如果obj内元素typeof返回值为'object',则递归调用deepCopy进行循环拷贝(数组和对象的typeof返回值都是'object')
result[item] = deepCopy(obj[item]) //递归
} else {
result[item] = obj[item] //直接赋值
}
}
return result
}
let result = deepCopy(obj);
console.log(result == obj) //false
obj.c[0].ca2 = '666' //改变obj
obj.c[1].cb2 = '666' //改变obj
console.log(result) //result不随着改变
console.log(obj) //obj改变了
打印结果
看起来有点眼花,哈哈哈,重点看改变的值,obj.c[0].ca2
和obj.c[1].cb2
。可以看出来,深拷贝中,obj===result打印的是false。因为深拷贝是直接复制堆中的数据对象,所以现在obj和result在堆中是两个不相干的数据对象。所以在代码中,当我们改变了obj中的ca2和cb2,result也不会发生变化。
深拷贝的方法有很多,但我感觉原生这种是最适用的,它可以提取出来作为一个公共方法使用。当然,JSON.parse(JSON.stringify())和lodash库中也都可以实现相应的深拷贝。
总结
深拷贝和浅拷贝的区别就是在于,浅拷贝是去复制存在于栈中的地址指向,所以新的变量和其都指向堆中的同一个数据对象。而深拷贝是直接在堆中复制出来一个新的数据对象,一份变成了两份,两者毫不相干。