object.assign仅复制自有可枚举属性,不操作原型链;正确用法是以{}为target合并实例对象,禁用原型对象作参数,深合并需专用方案。

Object.assign 本身不会复制原型链上的属性,所以它天然就不影响原型对象。你只需要确保目标对象和所有源对象都是普通实例对象(不是原型本身),合并操作就只作用于自有可枚举属性,完全绕过原型。
明确区分原型与实例对象
原型对象(如 Function.prototype、Array.prototype 或自定义构造函数的 MyClass.prototype)不应作为 target 或 source 传给 Object.assign。否则虽不报错,但会污染原型——这是严重反模式。
- ✅ 正确做法:在实例上合并,比如
const config = Object.assign({}, defaults, userOpts) - ❌ 错误做法:直接改原型,如
Object.assign(MyClass.prototype, mixin)(除非你明确要混入方法,且清楚后果)
合并时自动跳过原型属性
Object.assign 只遍历对象自身的、可枚举的属性(通过 Object.hasOwnProperty + propertyIsEnumerable 判断)。即使某个实例继承了原型上的方法或属性,这些都不会被复制过去。
例如:
const parent = { name: 'Parent' };
const child = Object.create(parent);
child.age = 25;
<p>Object.assign({}, child); // → { age: 25 }
// name 不出现,因为它来自原型,不是 child 自身属性</p>想安全地“增强”原型?用 defineProperty 而非 assign
如果真有需求向原型添加方法(比如封装工具函数),应使用 Object.defineProperty 显式控制属性特性(如 enumerable: false),而不是靠 assign —— 因为 assign 无法设置不可枚举属性,也不适合处理原型级定义。
Object.defineProperty(Array.prototype, 'last', { value() { return this[this.length - 1]; }, enumerable: false });- 这样添加的方法不会出现在
for...in或Object.assign的结果中
配置合并场景下的安全实践
常见用途是合并默认配置与用户选项,这时务必保证所有参与对象都是 plain object 实例:
- 用空对象
{}作 target,避免修改任何原始配置 - 确认
defaults和userOptions都是字面量或Object.create(null)创建的对象,不含意外原型链干扰 - 若需深合并嵌套结构(如
{ api: { timeout: 5000 } }),assign 不适用,应换用structuredClone+ 递归合并,或 Lodash_.merge
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











