深拷贝与浅拷贝
深拷贝与浅拷贝的区别
之所以会有深拷贝与浅拷贝之分,是因为不同数据类型的数据在内存中的存储区域不一样。
简单来说,假设B复制了A,当修改A时,看B是否会发生变化:如果B也跟着变了,说明这是浅拷贝;如果B没变,那就是深拷贝。
相关名词解释:堆栈,基本数据类型与引用数据类型
堆栈
堆和栈是计算机中划分出来用来存储的区域,其中堆(heap)则是动态分配的内存,大小不定也不会自动释放;而栈(stack)为自动分配的内存空间,它由系统自动释放。存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问。
基本数据类型
- 基本数据类型有:number、string、boolean、null、undefined五类(数据的原始值是大小确定不可变的,所以放在栈内存中)
- 基本类型的变量名和变量值都存储在栈内存中,当B复制A时,栈内存会新开辟一个内存,所以修改A对B无影响(算不上深拷贝,因为深拷贝这个概念是针对较为复杂的object类型数据)
引用数据类型
- 引用数据类型(Object类)有常规名值对的无序对象{a:1}、 数组[1,2,3]、以及函数等(类对象)
- 引用数据类型的“变量”名存在栈内存中,“变量”值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值。当B对A进行简单拷贝时,其实复制的是A的引用地址,而并非堆里面的值。由于A和B指向的是同一个地址,所以修改A时B也受了影响,这就是所谓的浅拷贝。
引用类型比较与基本类型变量之间相比较的区别
- 引用类型是引用的比较(两个独立的数组,即使包含的值完全相同,用==比较也会得到false)
- 基本类型间的比较是值的比较
几种“拷贝”的区别
赋值
引用类型的赋值,因为赋值操作只相当于是引用,两个变量还是指向同一对象,任何一方改变了都会影响到另一方
浅拷贝
对被拷贝对象的外层属性进行了复制,但对象的子类对象地址依然指向堆上的同一块内存地址
深拷贝
把对象以及对象的子对象进行拷贝,并在堆内存中也开辟一个新的内存专门为复制生成的B存放值(就像基本类型那样),就达到深拷贝的效果了
深拷贝的几种实现思路:
- 递归去复制所有层级属性;
- JS中使用JSON.stringify()和JSON.parse();
- Java中使用ObjectInputStream、ObjectOutputStream序列化对象再反序列化。
开发中的实际使用
例如后台返回了一堆数据,需要对这堆数据做操作,但多人开发情况下,是没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题,深拷贝能更安全安心的去操作数据。