structuredclone 会丢失 class 实例的原型,因为它仅克隆可传输值,排除函数、构造器、原型、symbol 键等;结果为无原型、无方法的 plain object,需手动重建实例或通过 fromplain 等方式恢复行为。

structuredClone 不会保留自定义 class 实例的原型,这是它的设计限制——它只序列化可传输的值(如 plain object、array、Date、Map、Set 等),而 class 实例被视为“不可克隆对象”,其原型链和方法会被丢弃,最终变成普通对象(plain object)。
为什么原型会丢失?
structuredClone 基于 结构化克隆算法,该算法明确排除了函数、class 构造器、原型属性、Symbol 键、undefined、window 对象等。当你传入一个 class 实例时:
- 实例自身的可枚举自有属性会被浅层复制(如果是嵌套对象则递归克隆)
- constructor、prototype、方法、getter/setter、私有字段(#field)全部不参与克隆
- 结果是一个没有原型、没有方法、只有数据属性的 plain object
如何保留原型和行为?
目前没有浏览器原生方式让 structuredClone 自动还原 class 原型。可行方案如下:
-
手动重建实例:克隆后用原始构造器 new 一个新实例,再 assign 数据属性
例如:const clone = Object.assign(new MyClass(), structuredClone(obj)) - 实现自定义 toJSON / fromJSON:在 class 中定义序列化逻辑,配合 structuredClone 处理数据部分,再由 fromJSON 恢复实例
-
使用支持 prototype 的第三方库:如
lodash.cloneDeep(但注意它也不保留方法,仅还原结构;若需完整行为,仍需配合 constructor 重建) - 避免依赖原型的方法调用:把业务逻辑抽离为纯函数,或确保关键状态都存在自有属性中(structuredClone 能保留这些)
一个实用的重建模式示例
假设你有:
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
greet() { return `Hello, ${this.name}!`; }
}
可以这样安全克隆:
- 先 structuredClone 得到纯数据对象
- 再 new User(...Object.values(clone)) 或 Object.assign(new User(), clone)
- 如果 class 有复杂初始化逻辑,建议加一个 static fromPlain(obj) 方法统一处理
注意边界情况
以下内容 structuredClone 一律无法处理,需额外设计:
- 私有字段(#name)、私有方法
- WeakMap / WeakSet(不可克隆)
- DOM 节点、RegExp(虽部分支持,但 RegExp 的 lastIndex 会重置)
- 循环引用(structuredClone 支持,但重建 class 实例时需自行维护引用关系)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











