定义
浅拷贝是在在拷贝过程中,遍历时那是将
新值指向旧值的存储地址。而深拷贝,则是完全开辟新的内存地址,再将
旧值完全拷贝过来
区别
浅拷贝的新值和旧值的地址指向是相同的。所以新值,旧值也会跟着改变,修改旧值也会改变新值。
而深拷贝的新值是放在一个全新的存储空间中,已经和旧值断了联系,修改哪一个,也不会改变另外一个。
补充
- 默认情况下基本数据类型(
number,string,null,undefined,boolean)都是深拷贝。 - 默认情况下引用类型(
object,array)都是浅拷贝。 - 基本数据类型,存放在栈内存中。引用数据类型,存放在堆内存中。
- 深拷贝和浅拷贝只是针对的是引用数据类型,如数组,对象等。基本数据类型没有深拷贝和浅拷贝之说,只是简单的赋值操作。
解构中的拷贝
解构赋值到底是深拷贝还是浅拷贝?
如果所解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,是深拷贝。
如果是多维数组或对象,其本质就是对引用类型数据进项等号赋值,是浅拷贝。
严格的来说:解构赋值是浅拷贝,因为它确实不能对多维数组或对象达到深拷贝的作用。
常用的深拷贝方法
在处理业务时,为了避免当修改一个变量的时候另一个变量也随着改变,所以常常会用到深拷贝。
最常用的方法是:
let b = JSON.parse(JSON.stringify(a));
这样就将a深拷贝给了b,其中的原理是:
JSON.stringify()⽅法⽤于将JavaScript 值转换为 JSON 字符串。
JSON.parse()方法将JSON格式字符串转换为js对象。解析前要保证数据是标准的JSON格式,否则会解析出错。
但是这个方法有着很大的弊端:
- 耗性能
- 需要拷贝的对象中不能有
JavaScript的关键字,否则会丢失。如一个对象中含有属性{foo:function(){}},再用此方法拷贝之后,拷贝后的对象会丢失掉foo这个属性
面试题:手写深拷贝实例
代码如下
function deepClone(source) {
//参数source为需要拷贝的对象或数组
//根据source的类型给予不同的容器
const targetObj = source.constructor === Array ? [] : {};
for (let keys in source) {
if (source.hasOwnProperty(keys)) { //判断这个属性是不是source独有的,这行代码可以根据情况决定是否使用
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys]) //递归
}else {
targetObj[keys] = source[keys]
}
}
}
return targetObj;
}