如何区分深拷贝和浅拷贝?
假设 B 复制了 A ,当 A 修改时,看 B 是否跟着发生改变
- 如果 B 改变了,说明是浅拷贝。
- 如果 B 没改变,说明时深拷贝。
首先,简单阐述栈堆,基本数据类型与引用数据类型。
因为这些概念能更好的让我们理解浅拷贝和深拷贝。
我们来举例浅拷贝的例子:
let obj = {
name: "张三",
habby: {
one: "旅行",
two: "摸鱼"
}
};
let newObj = {
...obj
};
newObj.habby.one = "打代码"; // 修改
console.log(obj); // 打印如下
微信截图_20200531000200.png
我明明 newObj 复制了 obj,为什么修改了 newObj ,obj 也跟着改变。那么这里,就得引入基本数据类型与引用数据类型的概念了。
基本数据类型有哪些?
number、string、undefined、null、symbol、boolean。
引用数据类型
array、object、function
微信截图_20200531000200.png基本数据类型:名值存储在栈内存中。
比如 let a = 1,当 b = a 复制时,栈内存会新开辟一个内存,例如这样:
2.png所以当你修改 a = 2,对 b 并不会造成影响。当然,let a = 1,b = a。虽然 b 不受影响,但这也不算是深拷贝,因为深拷贝本身只针对较为复杂的 object 类型数据。
3.png引用数据类型:名存在栈内存中,值存在于堆内存中。但是栈内存会提供一个引用的地址指向堆内存中的值。
当 b = a 进行拷贝时,其实复制的是 a 的引用地址,并非堆里面的值。
4.png而当我们a[0] = 1 时进行数组修改时,由于 a 与 b 指向的是同一个地址,所以自然 b 受了影响,所以这就是所谓的浅拷贝。
6.png那,要是在推内存也开辟一个新的内存专门为 b 存放值,就是基本数据类型那样,岂不是达到深拷贝的效果。
7.png方法一:通过递归去复制所有的层级属性实现深拷贝效果
function deepCopy(obj){
let newObj = Array.isArray(obj) ? [] : {};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] === "object"){
newObj[key] = deepCopy(obj[key]);
} else {
newObj[key] = obj[key];
}
}
};
return newObj;
};
let obj = {
name: "张三",
habby: {
one: "旅行",
two: "摸鱼"
}
};
let newObj = deepCopy(obj);
newObj.habby.one = '排球';
console.log(obj)
8.png
可以看到现在 obj 脱离了 newObj 的控制,不再受 newObj 的影响了。
方法二:通过 JSON 对象的 parse 和 stringify,缺点是对 function 和 undefined 无效。
let obj = {
name: "张三",
habby: {
one: "旅行",
two: "摸鱼"
}
};
let newObj = JSON.parse(JSON.stringify(obj));
newObj.habby.one = '排球';
console.log(obj);
9.png
可以看到 obj 不受 newObj 的控制了。
可以使用 localStorage实现对象数组存储,不过这里不多说,不太推荐。
最后,深拷贝能帮你更安全安心的去操作数据,根据实际情况来使用深拷贝。
网友评论