题目描述
js中引用类型的复制,浅拷贝,深拷贝过程中堆栈如何变化?
题目来源及自己的思路
在学习复制和浅拷贝的过程中,大部分博客都不清晰,把这两个混为一谈,所以请大佬们给我解析一下这三个的过程中,他们具体运行时堆栈里面有什么变化?
下面摘抄别人的博客
复制:当我们复制引用类型的变量时,实际上复制的是栈中存储的地址,所以复制出来的obj2实际上和obj指向的堆中同一个对象。因此,我们改变其中任何一个变量的值,另一个变量都会受到影响,这就是为什么会有深拷贝和浅拷贝的原因(复制我是理解的,但既然复制和浅拷贝都不一样了,为什么还要这样写?)。浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是引用类型,拷贝的就是内存地址
,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。(这个内存地址指的是堆中的地址吗?拷贝后在堆内存中又开辟一个新的存放还是别的?)
还有种说法:浅拷贝是一层的拷贝,深拷贝是多层的拷贝…这种说法和上述的说法到底谁对谁错?
我迷惑的是
1:括号里面的问题?
2:赋值和浅拷贝的区别到底在哪里?
4.如果浅拷贝的一层都拷贝了,为什么两个引用类型还会相互影响?
---------------v--------------
根据下面两位回答的理解补充:
5.赋值就等于浅拷贝?除了等号赋值之外还有其他浅拷贝方式吗?
6.那“浅拷贝是一层数据的拷贝,深拷贝是多层的拷贝…”这个话是错的?
7.那如果使用单层循环去给新对象赋值或者手动赋值的方法是就属于深拷贝,对吗?
//循环
let obj={a:1}, obj2 = {}
for (const key in obj) {
obj2[key] = obj[key]
}
obj2.a =2
console.log(obj);//{a: 1}
console.log(obj2);//{a: 2}
//赋值
let obj3 ={
a:obj.a
}
obj3.a = 3
console.log(obj);//{a: 1}
console.log(obj3);//{a: 3}
8.浅拷贝的大致流程就是:在栈内存分配内存来存储新对象的地址,而这个地址与原对象一致,指向原对象在堆内存的地址,堆内存不做操作。那浅拷贝数据obj = {a:1}时候原对象会随着新对象的值得改变而改变,对吗?
最重要的问题!!! 9:浅拷贝obj时多层属性时,其中堆栈变化是什么或者说怎么浅拷贝这个obj?
let obj = {a:1,b:{c:2},d:[1,2,3]}
各位大佬不用讲那么基础的,emmm我是懂那些的,只是因为网上的信息说法不统一,有些混乱了不知道正确的是什么了,以上几个问题,可以直接回答对或不对,错在哪里就可以了,码字不易很感谢你们,谢谢。
自答一下,我问了好几个人,回答方式都和上述几位一样,专门查了书,发现浅拷贝这里的东西没有具体定义,但是我更认可:引用类型的 赋值不等于浅拷贝和 浅拷贝是一层数据的拷贝,深拷贝是多层的拷贝这个观点。
赋值:新对象改变会影响原数据,原因引用类型在赋值的过程,只是把栈内存中的指针复制了一次,栈内存多了obj2,但是堆内存中的数据{a:1,b:{c:2}}没有改变,两个对象指向同一个堆内存地址。
MDN中数组的slice方法中有这句话 ,slice不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则浅拷贝...那就用slice来验证一下什么是浅拷贝:
这里
b[0] = 2;
时候a[0]没有随着改变,b[3].x = 2
时候a[3].x发生了变化。综上:我认为的浅拷贝:新的数据复制了原数据中 非对象属性的值 和 对象属性的引用,也就是说对象属性并不复制到内存,但非对象属性的值却复制到内存中。
而深拷贝会另外拷贝一份一个一模一样的对象,从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。