参考文章:
如何写出一个惊艳面试官的深拷贝?
前端手写系列01-深拷贝的两种实现与局限
手动实现一个深拷贝
深拷贝是什么?
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
深拷贝如何实现
需要注意的几点:
1、递归
2、判断类型
3、检查环(递归闭合无法结束)
4、忽略原型
最简单的实现:JSON.parse(JSON.stringify());
需要注意的是这样写的结果是JSON value不支持的数据类型,都拷贝不了。
简易代码:
function cloneDeep(target) {if (target === null) return null;if (typeof target !== 'object') return target;const newTarget = Array.isArray(target) ? [] : {};for (let key in target) {//不遍历其原型链上的属性if (target.hasOwnProperty(key)) {newTarget[key] = cloneDeep(target[key]);}}return newTarget;};
最终代码:
function cloneDeep(target, map = new Map()) {if (target === null) return null;if (typeof target !== 'object') return target;if (target.constructor === Date) return new Date(target);if (target.constructor === RegExp) return new RegExp(target);if (map.has(target)) return map.get(target);const newTarget = new target.constructor();map.set(target, newTarget);Reflect.ownKeys(target).forEach(key => {newTarget[key] = cloneDeep(target[key], map);})return newTarget;};
- 正确处理对象内的循环引用
- 保持之前的原型链
- 正确处理
bigint类型 - 正确处理 正则、Date 类型
- 正确处理
function、undefined类型 - 正确处理 key 为
symbol类型的字段
