深拷贝与浅拷贝
浅拷贝
浅拷贝就是拷贝第一层的基本类型值,以及第一层的引用类型地址。
如果属性是引用类型,拷贝的就是内存地址 ,所以其中一个对象改变了这个地址,就会影响到另一个对象。
即 浅拷贝只拷贝一层 ,而深拷贝是拷贝多层
Object.assign()
用于将所有可枚举属性的值从源对象复制到目标对象。它将返回目标对象。展开语法 Spread
Array.prototype.slice()
返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。
深拷贝
深拷贝是创建一个新的对象,将一个对象从内存中完整地拷贝出来一份给新对象,开辟一个新的区域存放新对象,且新对象的修改并不会改变原对象,二者实现真正分离。
一、 对象的深拷贝
序列化反序列化法
JSON.parse(JSON.stringify());
缺点:
number,string,array类似这样的能被json表示的数据类型,可以正常拷贝;
而函数、Date等, 这种不能被 json 表示的类型,将不能被正确处理。
undefined、symbol 和函数这三种情况,会直接忽略;
循环引用情况下,会报错;
不能正确处理new Date() 和 正则 ;
- tips:
但是!在工作中,这个深拷贝满足需求,最常使用。因为符合业务逻辑中的数据结构。
在复杂的深拷贝需求时,通常使用lodash库中的cloneDeep()更加稳定。
lodash 除了cloneDeep()常用之外,
还有chunk()用来将一维数组按照一定的规则变成二维数组,
debounce(),throttle(),
minBy()按照传入的属性找到属性值最小的对象
js实现深拷贝
思路
迭代递归法:
可以拆分成 2 步,浅拷贝 + 递归:
浅拷贝时判断属性值是否是对象,如果是对象就进行递归操作,两个一结合就实现了深拷贝。
考虑数组:
使用 typeof 来兼容数组
循环引用问题:
设置一个哈希表存储已拷贝过的对象,当检测到当前对象已存在于表中时,取出该值并返回即可。
可用数据结构WeakMap,以及它的方法has(),get(),set()来实现。
WeakMap vs Map
如果想要让垃圾回收器回收某一对象,就将对象的引用直接设置为 null
但如果一个对象被多次引用时,
例如作为另一对象的键、值或子元素时,
将该对象引用设置为 null,该对象也是不会被回收的,依然存在。
ES6 推出了: WeakMap
它对于值的引用都是不计入垃圾回收机制的,这是弱引用
弱引用是指当该对象应该被GC回收时不会阻止GC的回收行为
Map 相对于 WeakMap :
Map 的键可以是任意类型,WeakMap 只接受对象作为键(null除外),不接受其他类型的值作为键
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键; WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的
Map 可以被遍历, WeakMap 不能被遍历
拷贝Symbol:
Symbol 在 ES6 下才有,可以利用Object.getOwnPropertySymbols,查找有没有 Symbol 属性,如果查找到则先forEach遍历处理 Symbol 情况,然后再处理正常情况
代码实现
首先需要一个函数,对传入参数进行校验
没有对传入参数进行校验
1 |
|
深拷贝代码:
1 |
|
注意问题
for…in 会追踪原型链上的属性
需要拷贝不可枚举的属性
比如需要拷贝类似属性描述符,setters 以及 getters 这样不可枚举的属性。这就需要一个额外的不可枚举的属性集合来存储它们。Object.create() 的第二个参数
除了对象的原型,Object.create方法还可以接受第二个参数。
该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性。
1 |
|
一些特殊类型的数据需要特殊照顾
Date和RegExp对象类型
日期 或 正则对象,直接构造一个新对象返回if([Date,RegExp].includes(source.constructor)) return new source.constructor(source);函数对象
if(typeof source == 'function') return new Function('return' + source.toString())();Map对象
1 |
|
- Set对象
if(source instanceof Set) {
const result = new Set();
source.forEach((value)=>{
if(isObject(value)) {
result.add(cloneDeep(value));
} else {
result.add(value);
}
});
return result;
}
- 本文作者:JSZ
- 本文链接:blog.vampuck.com/2022/06/16/copy/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!