JavaScript 深拷贝
定义
深拷贝:完全复制对象及所有嵌套结构,新旧对象相互独立(修改新对象不影响原对象)。
一、基础方法(简单场景)
1. JSON.parse(JSON.stringify())
用法:
const deepCopy = JSON.parse(JSON.stringify(original));优点:简单易用,无需依赖。先转换为json格式,再转换为js对象。
局限性:
- 不支持
Function、RegExp、Date、Map、Set等特殊类型; - 忽略
undefined、Symbol属性; - 循环引用(如
obj.self = obj)会报错; - 不拷贝原型链。
- 不支持
二、手动递归实现(灵活可控)
1. 基础版(处理对象 / 数组)
function deepClone(target) {
if (target === null || typeof target !== 'object') return target;
const cloneTarget = Array.isArray(target) ? [] : {};
for(const key in target){
cloneTarget[key] = deepClone(target[key]);
}};
return cloneTarget;
}
2. 增强版(解决循环引用 + 特殊类型)
通过weakMap缓存已经处理/拷贝过的对象,添加一层判断是否已经拷贝过,如果拷贝过直接返回
function deepClone(target, map = new WeakMap()) {
if (target === null || typeof target !== 'object') return target;
if (map.has(target)) return map.get(target); // 解决循环引用
let cloneTarget;
// 处理 Date/RegExp 等特殊类型
if (target instanceof Date) cloneTarget = new Date(target);
else if (target instanceof RegExp) cloneTarget = new RegExp(target.source, target.flags);
else cloneTarget = Array.isArray(target) ? [] : {};
map.set(target, cloneTarget);
Reflect.ownKeys(target).forEach(key => {
cloneTarget[key] = deepClone(target[key], map);
});
return cloneTarget;
}
三、工具库(生产环境推荐)
1. Lodash _.cloneDeep()
import _ from 'lodash';
const deepCopy = _.cloneDeep(original);
- 支持几乎所有类型(
Map、Set、Symbol等),处理循环引用。
2. Ramda clone
import { clone } from 'ramda';
const deepCopy = clone(original);
四、JS原生 API(现代浏览器/Node.js)
1. structuredClone()
const original = {
date: new Date(),
reg: /pattern/gi,
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3])
};
const deepCopy = structuredClone(original);
特性:
- ✅ 支持复杂类型(
Date、RegExp、Map、Set、ArrayBuffer等) - ✅ 处理循环引用
- ✅ 浏览器原生实现,性能优秀
- ❌ 不支持函数、DOM 元素、原型链
适用场景:
- 需要完整保留复杂类型的深拷贝
- 状态管理中的状态快照
- 高性能深拷贝需求
五、注意事项
- 循环引用:需用
WeakMap缓存已拷贝对象,避免递归死循环; - 原型链:默认不拷贝,需手动处理(如
Object.setPrototypeOf); - 特殊对象:
Blob、DOM 元素等需调用对应构造函数复制。
场景选择
- 简单场景:
JSON.parse(JSON.stringify()); - 复杂场景:Lodash
_.cloneDeep()或增强版手动实现。