一、在探讨深浅拷贝的问题之前需要先理解两种数据类型
- 值类型数据(基本数据类型):存储在栈内存,占据固定大小的空间,直接存储其数据(值的赋值是深拷贝);
- 引用类型数据:这种数据类型的变量通常存储在栈区,存的是指向实际数据的指针,而实际的数据是存储在堆区,访问数据通过指针去访问(值的赋值可以是浅拷贝也可以是深拷贝);
二、深拷贝 VS 浅拷贝
深拷贝
- 深拷贝是在内存中重新开辟了一个新的内存空间来存储数据
浅拷贝
- 浅拷贝是多个指针指向一份共同的内存
举例
-
值类型的深拷贝:比如 a = 10 ,这里的数据a是值类型,直接存储数字10,存储在栈区的某个地方,暂且叫做k区域,当赋值操作b = a 的时候实际是重新在内存中开辟了一份新的空间m区域,存储的值也是10,这个时候 a = 10 ,b也等于10,更改a或者b的值不会相互影响,值类型赋值都会重新开辟一个新的存储空间,所以不存在浅拷贝。
-
引用类型数据:比如a = [1,3,4,4],这里a是指针,存储在栈区,数组[1,3,4,4]是指针a指向的数据,存储在堆区,当要访问数组的时候通过指针a去访问,现在如果把a的值深拷贝给b,相当于在堆区开辟了一个新的空间,存储新的一份数组[1,3,4,4],这个时候实际的数据在堆区就有两分,a指向一份,b指向一份。但是假如把a的值浅拷贝给b,那实际上做的事情是把指针b也指向了a指向的那个数组[1,3,4,4],结果是a、b指向的是同一份内存,当改变a的值b也会跟着改变。总结一下,深拷贝操作的是实际存储的数据,把数据复制一份或者多份出来分别存储,而浅拷贝实际上只是移动了指针,把多个指针指向同一份数据,所以在浅拷贝复制的时候往往速度会更快。
三、不同语言之间实现深浅拷贝
-
Object-C:
-
值类型数据:数值型、字符型(char)、bool、void
-
引用类型: 包括类类型(如NSString、NSArray、NSDictionary等)和块类型(block)
-
oc深浅拷贝较复杂,其实可以把copy 和 mutableCopy统统归为浅拷贝,因为他们要么是指针的复制,也就是完全的浅拷贝,要么只是是拷贝一层,没有完全实现深拷贝,归档才是真正意义上的深拷贝,
- 拷贝一层或者浅拷贝:【a copy】 或者【a mutableCopy】,例如调用NSArray的mutableCopy方法时,将会返回一个NSMutableArray对象,表面看这个是深拷贝,因为确实是复制了一份内存出来,但是实际上他只是拷贝了一层,比如数组里是字符串,那两分内存数组中的字符串指向的是同一份地址。
- 拷贝两层:[[数据类型对象 alloc]initwith:拷贝目标 copyitems:yes]
- 深拷贝:归档[nskeyedunarchiver unarchiveobjectwithdata:[nskeyedarchiver archiveddatawithrootobject:拷贝目标]]
-
-
python:
-
值类型数据:
- 整数(int)
- 浮点数(float)
- 复数(complex)
- 字符串(str)
- 布尔值(bool)
- 空值(None)
-
引用数据类型:
- 列表list
- 元组tuple
- 字典dict
- 集合set
-
浅拷贝:copy()
-
深拷贝:deepcopy()
-
-
js:
-
值类型数据:Number string null undefined boolean Symbol(ES6)、Bigint(ES10)
-
引用数据类型:Array Object function
-
浅拷贝:
- 直接赋值(直接赋值只是指针的复制,比如a指向一个地址,赋值a给b,实际含义是b直接指向a指向的地址)
- slice()
- concat()
- Array.from
- Object.assign:对象合并
-
深拷贝
- 序列化
- JSON.stringfy() 将对象序列化成json对象,
- JSON.parse() 反序列化——将json对象反序列化成js对象
- 序列化
-