json.parse(json.stringify(obj))不是真正深拷贝:会丢失函数/undefined/symbol、抹平原型链与特殊对象(如date变字符串、regexp变{})、循环引用直接报错,且不支持bigint、nan/infinity转null等。

JavaScript 中实现一个简单的深拷贝函数,最直接可靠的方式是使用 JSON.parse(JSON.stringify(obj)),但它有明显限制(比如无法处理函数、undefined、Symbol、Date、RegExp、循环引用等)。如果需要更健壮的简易版本,推荐手写递归实现,兼顾可读性与基础兼容性。
基础递归深拷贝(支持对象、数组、基本类型)
这个版本能正确处理普通对象、数组、null、基本类型,同时避免引用共享,适合大多数日常场景:
function deepClone(obj) {
// 处理 null、非对象(如 string/number/boolean)直接返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 区分数组和普通对象
const cloned = Array.isArray(obj) ? [] : {};
for (const key in obj) {
// 只遍历自身属性
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]); // 递归拷贝每个值
}
}
return cloned;
}
注意事项和常见坑
这个简易实现虽轻量,但仍有几个关键点需留意:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
不处理特殊对象:Date、RegExp、Map、Set、Promise 等会变成空对象或丢失类型(例如
new Date()拷贝后变成{}) -
不处理循环引用:若对象内部存在自引用(如
obj.a = obj),会触发栈溢出 - 忽略不可枚举属性和原型链上的属性:只拷贝自有可枚举属性,符合多数预期
- 函数会被忽略(变为 undefined):因为函数在 JSON 序列化中被丢弃,而本递归版也未特殊处理函数类型
增强一点:支持 Date 和 RegExp
只需在开头加几个 instanceof 判断,就能安全保留常用内置类型:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
// 特殊对象类型单独处理
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const cloned = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
什么时候该用现成方案?
如果项目中需要真正健壮的深拷贝(如处理循环引用、各种内置类型、不可枚举属性),建议直接使用成熟库:
-
Lodash 的
_.cloneDeep():覆盖全面,经过大量测试 - structuredClone()(现代浏览器 & Node.js 17.0+):原生 API,支持 Map/Set/Date/BigInt 等,但暂不支持函数和循环引用(部分环境已支持)
自己写的简易版更适合学习、调试、或约束明确的内部数据结构(如纯 JSON 风格配置对象)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










