structuredclone能保留原型链并安全处理循环引用,是处理复杂原型引用深度克隆的首选方案;它支持date、map、set、regexp等内置类型,但不支持函数、symbol、undefined、error和dom节点。

处理复杂原型引用的深度克隆,核心在于两点:保留原对象的原型链,同时避免因循环引用导致栈溢出或无限递归。现代方案优先用 structuredClone(),它天然支持原型继承(对可结构化对象)和循环引用;若需兼容旧环境或自定义行为,则必须手动重建原型链并缓存已克隆对象。
用 structuredClone() 保真克隆(推荐首选)
该 API 是当前最可靠、最简洁的方案,能完整保留 Date、Map、Set、RegExp、ArrayBuffer 等内置类型,也支持嵌套对象的原型链继承(前提是这些对象属于“可结构化数据”范畴)。它自动检测并安全处理循环引用,无需额外逻辑。
- 浏览器支持:Chrome 98+、Firefox 94+、Safari 15.4+,Node.js 18.16+ / 20.6+ 已稳定支持
- 不支持函数、Symbol、undefined、Error 实例、DOM 节点等非结构化值——这本身是设计约束,不是缺陷
- 示例:
const clone = structuredClone(originalObj);即可完成,clone instanceof originalObj.constructor在多数情况下仍为 true
手动实现:保持原型链 + 防循环引用
当需要克隆含函数、自定义类实例、Symbol 属性,或需精细控制拷贝逻辑时,需手写递归函数。关键步骤包括:
- 用
Object.getPrototypeOf(obj)获取原原型,再用Object.create(proto)创建新对象并继承该原型 - 使用
WeakMap缓存已处理对象,每次进入递归前先查缓存,命中则直接返回,彻底阻断循环引用 - 区分构造器类型:对
Date、RegExp、Map、Set等分别构造新实例并深拷贝其内容;对普通对象和数组则遍历自身属性(含 Symbol 键) - 注意:函数无法真正“克隆”,只能复制引用;若需隔离行为,应重新定义或封装
JSON 方法为何不适合原型场景?
JSON.parse(JSON.stringify(obj)) 会完全丢失原型信息——生成的对象总是 Object.prototype 的实例,且所有非基本类型(Date、RegExp、Map、函数、Symbol、undefined)都会被忽略、转换或丢弃。
- 例如:
new Date()变成 ISO 字符串,不再有.getTime()方法 - 自定义类实例变成纯字面量对象,
instanceof MyClass返回 false - 遇到循环引用直接抛错:
TypeError: Converting circular structure to JSON
原型链与继承的实际影响
如果只关心数据副本是否独立,不依赖原型方法,那多数场景下 structuredClone() 或简化版递归已足够。但若对象行为依赖原型上的方法(如 obj.toString() 或自定义工具方法),就必须确保克隆后仍能沿原型链访问——这正是手动实现中 Object.create(Object.getPrototypeOf(obj)) 的意义所在。
不复杂但容易忽略的是:仅复制属性不等于继承行为,原型链才是方法查找的路径。克隆不是“复制代码”,而是“重建关系”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











