深拷贝时原型方法被错误拷贝到自身,本质是混淆自有属性与原型属性;应仅遍历自有属性(用object.keys等),重建实例或object.create绑定原型,避免json或展开运算符。

深拷贝时原型方法被“错误拷贝到自身”,本质是混淆了“自有属性”和“原型链上的方法”。JavaScript 中方法通常定义在原型上(如 MyClass.prototype.method),而非实例自身。若拷贝逻辑把原型上的方法当作普通属性复制到新对象的 [[OwnKeys]] 中,就会破坏继承结构:方法变成实例自有属性,instanceof 失效,无法响应后续原型更新,且可能覆盖同名自有字段。
明确区分自有属性与原型属性
拷贝前必须只遍历对象自身的可枚举/不可枚举属性,跳过原型链。不要用 for...in(会遍历原型),而应使用:
-
Object.keys(obj)—— 仅自有可枚举属性 -
Object.getOwnPropertyNames(obj)—— 自有所有属性(含不可枚举) -
Object.getOwnPropertySymbols(obj)—— 自有 Symbol 属性 - 配合
Object.getOwnPropertyDescriptors(obj)获取完整描述符(含 getter/setter、writable 等)
避免任何直接读取 obj.method 并赋值给新对象的操作——这会把方法变成自有属性,切断原型继承。
重建实例而非复制方法
正确做法不是“拷贝方法”,而是重建具有相同原型链的新实例:
- 用原构造函数创建空实例:
const cloned = new obj.constructor() - 再用
Object.assign(cloned, obj)或逐个设置自有属性(不包括函数) - 确保
cloned的[[Prototype]]指向obj.constructor.prototype,而非Object.prototype
这样方法仍从原型链调用,cloned instanceof obj.constructor 为 true,且修改 MyClass.prototype.method 会影响所有实例。
用 Object.create 显式绑定原型
当构造函数不可安全调用(如含副作用),或需兼容继承链(如子类实例),优先用原型对象创建新实例:
- 获取原对象原型:
const proto = Object.getPrototypeOf(obj) - 创建继承该原型的新对象:
const cloned = Object.assign(Object.create(proto), obj) - 手动修复
constructor(若需要):cloned.constructor = obj.constructor
此方式完全绕过构造函数执行,保留完整的原型链层级(例如 Admin → User → Object),所有原型方法自然可用。
避开 JSON 和简单展开运算符
JSON.parse(JSON.stringify(obj)) 和 {...obj} 都会把原型方法丢弃,再反向“恢复”时只能靠手动挂载——这极易出错且违背面向对象设计。它们只适合纯数据对象(POJO)。一旦对象有行为(方法)、状态(闭包)、类型语义(instanceof 判断),就必须放弃这类方案。
现代环境优先用 structuredClone(obj):它原生保留原型链,对自定义类实例、内置类型(Date、RegExp 等)都保持类型完整性,且自动处理循环引用。仅需确认目标对象不含函数、Symbol 或 DOM 节点即可。











