赋值
b = a
赋值 = 是将某一数值或对象赋给某个变量的过程,分为下面 2 部分
- 基本数据类型:赋值,赋值之后两个变量互不影响
- 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响
1 | let c = 1; |
因为基本类型值不会随之改变,因此下面的浅拷贝和深拷贝是针对对象类型的。
浅拷贝
b = a.slice()
浅拷贝即创建一个新对象,改变新对象的基本类型值,原对象不会随之改变,但如果改变新对象中引用类型内的值,原对象也会随之改变。Object.assign()
就是浅拷贝,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
1 | let a = { |
同理,对于对象类型下的数组,slice()
、concat()
、...运算符
经过测试后发现都是浅拷贝
1 | let arr1 = [1 , 2 , 3 , {"name" : "张一"} , {"sex" : "male"}]; |
1 | let arr2 = arr1.slice(); |
这里推荐使用扩展运算符…来进行浅拷贝({}、[]都推荐…),而不是Object.assign,详情请看下面的代码
Prefer the object spread operator over Object.assign
to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.
1 | // very bad |
深拷贝
b = cloneDeep(a)
深拷贝即完全改变变量 b 之后对 a 没有任何影响。深拷贝相比于浅拷贝速度较慢并且花销较大。
JSON.parse+JSON.stringify
1 | let a = { |
1 | let arr1 = [1 , 2 , 3 , {"name" : "张一"} , {"sex" : "male"}]; |
这个方法很简便,但是有以下几个问题。
1、会忽略 undefined
2、会忽略 symbol
3、不能序列化函数
4、不能解决循环引用的对象
5、不能正确处理new Date()
6、不能处理正则
DFS
浅拷贝 + 递归
这里呢只实现最简单的深拷贝,只考虑 数组
和{}
的情况,并且没有循环引用
1 | typeof null //"object" |
1 | function isObject(obj) { |
小结
– | 和原数据是否指向同一对象 | 第一层数据为基本数据类型 | 原数据中包含子对象 |
---|---|---|---|
赋值 | 是 | 改变会使原数据一同改变 | 改变会使原数据一同改变 |
浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变会使原数据一同改变 |
深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |
参考