javascript深拷贝默认不复制原型链上的属性,因其本质是共享行为机制而非实例数据;structuredclone、json方法等均只处理自有可枚举属性,忽略原型;需保留原型时应手动用object.create重建并深拷贝自有属性。

JavaScript 深拷贝默认不复制原型链上的属性,这是关键前提。原生方法如 structuredClone、JSON.parse(JSON.stringify()) 和大多数手动递归实现,都只处理对象的**自有可枚举属性**(own enumerable properties),完全忽略 __proto__、Object.getPrototypeOf(obj) 上定义的方法或数据。
为什么原型属性通常不被深拷贝
原型链本质是共享行为和状态的机制,不是实例数据的一部分。深拷贝的目标是创建“独立副本”,而非重建继承关系。若自动复制原型,可能引发意料外的行为:比如重复绑定事件监听器、意外继承私有符号属性、或破坏单例/缓存逻辑。
-
structuredClone:明确不保留原型,结果对象的原型总是
Object.prototype - JSON 方法:序列化时只遍历自有可枚举属性,原型属性天然丢失
- Object.assign / 扩展运算符:仅拷贝自有属性,且是浅拷贝,更不涉及原型
需要保留原型时的手动控制方式
若业务场景确需新对象继承原对象的原型(例如克隆一个带自定义构造函数的实例),必须显式处理:
- 用
Object.create(Object.getPrototypeOf(original))创建新对象,确保原型链一致 - 再将原对象的自有属性(含 Symbol 键)递归深拷贝到该新对象上
- 对特殊内置类型(Date、RegExp、Map、Set 等)单独判断并新建实例,避免直接赋值引用
- 使用
WeakMap缓存已处理对象,防止循环引用导致栈溢出
实际中更推荐的替代思路
多数情况下,与其强行复制原型,不如重构设计:
- 把可复用逻辑放在工厂函数或类的静态方法中,而非依赖原型共享
- 用组合代替继承,将行为封装为独立模块,通过属性注入而非原型链获取
- 若必须克隆实例且保留行为,优先调用实例自身的
clone()方法(如有),由类自己控制哪些状态要复制、哪些应重置或共享
原型不是数据,而是契约。深拷贝专注数据隔离,原型继承专注行为复用——两者职责不同,混用反而增加复杂度。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











