数据类型
在了解深、浅拷贝之前,得先了解 JavaScript 中的数据类型和存储方式
基本类型:
number、string、boolean、null、undefined、symbol- 存储在栈内存中
 - 大小固定、体积轻量、相对简单
 - 赋值操作会直接生成一个新的值(深拷贝)
 
引用类型:
object、array、function等- 栈存储该对象的引用地址,实际数据存放在堆内存
 - 大小不定、占用空间较大、比较复杂
 - 赋值操作会直接将指针指向该实体的引用地址(处于节省内存考虑,属于浅拷贝)
 
深浅拷贝定义
浅拷贝:复制某个对象的指针地址,而不是复制对象本身,新旧对象依然共享一块内存
深拷贝:创造一个一模一样的对象,新对象与原对象不共享内存,修改新对象不影响到原对象
浅拷贝
Array
slice()
1  | function cloneArrayBySlice(list){  | 
concat
1  | function cloneArrayByConcat(list){  | 
spread
1  | function cloneArrayBySpread(list){  | 
Object
assign
值得注意的是 assign 接受第一个入参为 target 后续的参数为混入到 target 上,所以也算一种浅拷贝吧(勉强)
1  | function assign(obj){  | 
深拷贝
assign
为什么这里还能出现在这个?
Object.assign方法只会拷贝源对象自身的并且可枚举的属性到目标对象
1  | var a = { a: 1 }  | 
当然它只要超过值是引用类型还是执行浅拷贝
1  | var a = { a: 1, b: { b : 2 } }  | 
JSON.parse
这个方法的原理是将对象序列化成字符串,再解析 json 字符串解析为对象
1  | function clone(obj){  | 
缺点
- 忽略 
symbolundefinedfunction类型 - 不支持循环引用对象的拷贝
 
MessageChannel
Channel Messaging API的 MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据
1  | var { port1, port2 } = new MessageChannel()  | 
1  | function clone(obj){  | 
缺点
- 异步取值
 - 不支持 
function和symbol类型 
递归遍历
使用递归去创建对象,再赋值,可以处理大部分场景
1  | function clone(obj) {  | 
缺点
- 不支持循环引用
 
处理循环引用的解决方案
使用 WeakMap 数据结构存储循环引用的映射关系
1  | function clone(obj){  | 
测试用例
1  | const { clone } = require('./clone.js')  |