原型链复制需行为克隆而非浅拷贝:须识别原型链属性、保留特殊类型语义、处理循环引用、维持方法调用能力;structuredclone最接近需求,但需结合setprototypeof和自定义逻辑补全函数与原型方法。

在设计模式中,原型链复制(Prototype Pattern)依赖对象克隆来创建新实例。若仅用浅拷贝,嵌套对象仍共享引用,破坏“行为独立性”这一核心目标。要实现真正深层次的行为克隆,关键不是单纯复制数据结构,而是确保:原型链上所有可继承属性被正确识别、特殊类型(如函数、Date、RegExp)保留行为语义、循环引用不导致崩溃、且克隆后的新对象能完整响应原型方法调用。
必须避开原型链污染与属性丢失
原生浅拷贝方法(Object.assign()、扩展运算符)默认忽略原型链上的属性,也跳过 Symbol 键和不可枚举属性。而原型模式恰恰依赖这些——比如一个带 clone() 方法的基类,该方法定义在 Parent.prototype 上。若深拷贝只处理自有属性,新对象将丢失该方法,无法继续参与原型链行为。
- 使用 Object.getOwnPropertyDescriptors() + Object.defineProperties() 复制自有属性(含 getter/setter、writable/enumerable 状态)
- 显式遍历原型链:
Object.getPrototypeOf(obj)逐层获取并复制可枚举+不可枚举的自有属性(需配合Object.getOwnPropertyNames()和Object.getOwnPropertySymbols()) - 对函数属性,不能简单
obj[key].toString()再eval,应直接赋值引用——函数本身是可克隆的值,只要不修改其闭包环境,行为即保持一致
structuredClone 是最接近“行为克隆”的原生方案
structuredClone() 虽不复制函数和原型方法,但它能完整保留 Date、RegExp、Map、Set、ArrayBuffer 等内置对象的实例类型与行为(如 date.toLocaleString()、regex.test() 依然可用)。这意味着:若原型中封装的是对这些类型的操作逻辑(例如一个日期格式化器类),克隆后的对象仍能正确执行原型方法。
- 它自动处理循环引用,避免递归栈溢出
- 不丢失
undefined、BigInt、NaN、Infinity等边界值 - 克隆结果是全新对象,与原对象无内存共享,满足“行为隔离”前提
自定义 deepCloneWithPrototype 需分层构造
若需完整保留函数和原型方法(例如克隆一个带私有状态和公共接口的类实例),不能只靠数据拷贝,而应结合构造逻辑:
- 第一步:用 structuredClone() 深拷贝所有可序列化字段(数据态)
- 第二步:手动重建原型关系:
Object.setPrototypeOf(cloned, Object.getPrototypeOf(original)) - 第三步:对不可克隆项(如函数、DOM 节点、WeakMap)做策略性处理——或跳过,或注入代理存根,或由类自身提供
clone()钩子方法 - 推荐在构造函数中定义静态
from()或实例clone()方法,把克隆逻辑内聚到类内部,而非依赖通用工具函数
不要用 JSON.parse(JSON.stringify()) 做原型克隆
它会把 Date 变成字符串、RegExp 变成空对象、function 直接消失、undefined 被过滤、Symbol 键丢失、原型链彻底断裂。克隆后的对象连 instanceof 判断都会失败,更谈不上“行为克隆”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











