Object.assign不处理原型,只复制自身可枚举属性;解决原型继承需手动设置原型、用Object.create创建新对象,或使用structuredClone进行结构化克隆。

Object.assign 默认只复制对象自身的可枚举属性,不会拷贝原型链上的属性,也不会保留目标对象的原型。要解决“原型丢弃”问题,不能靠 Object.assign 本身修复,而需在复制后手动恢复原型,或改用其他方式实现带原型继承的浅拷贝。
理解 Object.assign 的行为本质
Object.assign(target, ...sources) 执行的是:
- 遍历 sources 中每个对象的自身可枚举属性(不包括原型链上的)
- 将这些属性逐个赋值给 target(使用 = 赋值,不是 defineProperty)
- target 的原型始终是它原来的 prototype,不会因复制而改变
也就是说:原型没被“丢弃”,而是压根就没被“处理”——Object.assign 根本不关心原型。
方案一:复制后手动设置原型(最直接)
适用于已知源对象构造函数、且目标对象需继承同一原型的场景:
立即学习“Java免费学习笔记(深入)”;
const source = new Date(); // 原型是 Date.prototype
const target = {};
Object.assign(target, source); // 只复制了时间戳等自有属性
Object.setPrototypeOf(target, Object.getPrototypeOf(source)); // 恢复原型
// 现在 target instanceof Date === true
注意:Object.setPrototypeOf 性能较低,不建议在热路径频繁调用;生产环境更推荐用 Object.create + assign 组合。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
方案二:用 Object.create 创建带正确原型的新对象
更安全、更符合原型继承语义的做法:
function cloneWithPrototype(obj) {
const proto = Object.getPrototypeOf(obj);
const cloned = Object.assign(Object.create(proto), obj);
return cloned;
}
const source = { a: 1 };
source.__proto__.b = 2; // 假设 b 在原型上
const copy = cloneWithPrototype(source);
console.log(copy.a); // 1(自有)
console.log(copy.b); // 2(可从原型访问)
console.log(Object.getPrototypeOf(copy) === Object.getPrototypeOf(source)); // true
这个方法确保新对象与原对象共享同一原型,且自有属性完整复制。
方案三:用结构化克隆(现代环境首选)
如果只是想深拷贝并保留原型(如 Map、Set、Date、RegExp 等内置类型),可用 structuredClone(ES2022+):
const source = new Date('2023-01-01');
const copy = structuredClone(source); // 类型、原型、值全部保留
console.log(copy instanceof Date); // true
限制:仅支持可结构化克隆的类型(不支持 function、undefined、BigInt(旧版)、循环引用(新版已支持)等),也不支持自定义类实例的原型方法,但对大多数内置对象足够健壮。
不复杂但容易忽略:原型不是被“丢弃”了,而是 Object.assign 本来就不动它;真正要做的,是明确你想要的继承关系,再选择 setPrototypeOf、Object.create 或 structuredClone 来达成目的。

















