object.assign无法保留源对象原型,因其仅复制自身可枚举自有属性,忽略原型链;需用object.create+object.assign等方法实现原型继承。

Object.assign 无法保留源对象的原型,这是它固有的行为,不是用法问题。它只复制源对象自身的、可枚举的自有属性,完全忽略原型链上的任何内容(包括方法、访问器、继承来的属性)。
为什么原型不会被复制
Object.assign 的设计目标就是“浅拷贝自有属性”,不涉及原型操作。它的内部逻辑等价于手动遍历 Object.keys(source)(或 for...in 配合 hasOwnProperty),而 Object.keys 和 hasOwnProperty 天然只返回/检查对象自身的可枚举属性,跳过原型链。
例如:
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { return `${this.name} makes a sound`; };
const dog = new Animal('Buddy');
const copy = Object.assign({}, dog);
console.log(copy.name); // 'Buddy' ✅ 自有属性被复制
console.log(copy.speak); // undefined ❌ 原型方法丢失
console.log(copy.__proto__ === Object.prototype); // true —— copy 是纯 plain object,无 Animal 原型
想保留原型,得换方法
如果目标是创建一个新对象,既拥有源对象的自有属性,又继承其原型,就不能用 Object.assign,而应选择以下方式:
-
Object.create + Object.assign:先用
Object.create(source.__proto__)创建带正确原型的新对象,再用Object.assign把自有属性复制过去 -
构造函数调用:若知道源对象的构造器(如
dog.constructor),可用new dog.constructor(...)实例化,再合并属性 - Reflect.construct(ES2015+):更安全地重建实例,尤其适用于带参数或 Symbol.species 的类
-
直接设置原型(不推荐):
Object.setPrototypeOf(target, source.__proto__),但会带来性能开销且不可枚举
常用安全写法示例
保留原型并合并自有属性的典型组合:
function cloneWithPrototype(obj) {
const clone = Object.assign(
Object.create(Object.getPrototypeOf(obj)), // 新对象,原型 = obj 的原型
obj // 复制自有可枚举属性
);
return clone;
}
const dog = new Animal('Buddy');
const clonedDog = cloneWithPrototype(dog);
console.log(clonedDog.speak()); // 'Buddy makes a sound' ✅
console.log(clonedDog instanceof Animal); // true ✅
注意边界情况
某些对象没有标准原型(如 Object.create(null) 创建的对象),或原型为 null,此时 Object.getPrototypeOf(obj) 返回 null,Object.create(null) 仍有效,不会报错。但像 document、window 等宿主对象的原型行为可能不一致,不建议对其做此类操作。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











