手动实现深拷贝的核心是准确识别类型、安全构造副本并拦截循环引用;需先判断类型,仅对引用类型递归,用weakmap处理循环,按类型分发构造新实例并保留原型链与特殊属性。

手动实现 JavaScript 深拷贝,核心不是“写递归”,而是准确识别类型、安全构造副本、并拦截无限循环。它适合需要兼容老环境、定制行为(比如过滤字段、转换日期格式)或学习原理的场景,但不推荐在生产中替代成熟方案。
必须先做类型判断和快速返回
深拷贝只对引用类型有意义。所有基础值(string、number、boolean、symbol、bigint、undefined、null)和函数都直接返回,不进入递归:
-
typeof obj === 'object' && obj !== null 是进入拷贝逻辑的唯一安全前提——因为
typeof null也是'object' - 用
Object.prototype.toString.call(obj)精确识别内置对象,比instanceof更可靠(避免跨 iframe 问题) - 函数(
typeof obj === 'function')通常直接返回原引用;如需复制,需明确策略(如重定义、跳过或报错)
按类型分发构造新实例
不能统一用 {} 或 JSON.stringify,必须针对不同构造器创建对应副本:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
数组:用
Array.from(obj)或obj.map(item => deepClone(item, cache)),保留稀疏数组特性 -
Date / RegExp:直接
new obj.constructor(obj),简洁且保留原始状态 -
Map / Set:用
new Map(obj.entries())或new Set(obj.values()),entries/values 方法已递归处理键值 -
普通对象:用
Object.create(Object.getPrototypeOf(obj))继承原型,再用Object.getOwnPropertyDescriptors()获取所有自有属性(含 getter/setter、不可枚举项),最后Object.defineProperties()安装
用 WeakMap 解决循环引用
当对象 A 引用 B,B 又引用 A(或自引用),不加控制会栈溢出。WeakMap 是唯一安全的缓存方式:
- 每次递归前查
cache.has(obj),存在则直接返回缓存结果 - 新建副本后立即
cache.set(obj, result),确保后续遇到同一对象时能命中 - WeakMap 不阻止垃圾回收,不会造成内存泄漏,比 Map 更适合临时映射
不拷贝但可保留原型链
深拷贝目标是复制“值”,不是模拟继承关系。但某些场景(如 instanceof 判断)需要保持 constructor 行为:
- 新建对象后调用
Object.setPrototypeOf(result, Object.getPrototypeOf(obj)),显式设置原型 - 不拷贝原型上的属性或方法——那属于浅拷贝或继承范畴,与深拷贝语义冲突
- Symbol 键、不可枚举属性、访问器属性(getter/setter)需通过
getOwnPropertyDescriptors显式获取并定义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










