Object.assign 和对象扩展运算符(...)在功能上非常相似,都用于浅拷贝对象属性。它们的主要区别在于语法、使用场景和一些细微的行为差异。
1. 功能与相似性
两者都用于将一个或多个源对象的可枚举属性复制到目标对象中,实现浅拷贝(Shallow Copy)。
const obj1 = { a: 1 };
const obj2 = { b: 2 };
// 使用 Object.assign
const merged1 = Object.assign({}, obj1, obj2); // { a: 1, b: 2 }
// 使用扩展运算符
const merged2 = { ...obj1, ...obj2 }; // { a: 1, b: 2 }
2. 主要区别
| 特性 | Object.assign | 对象扩展运算符 (...) |
|---|---|---|
| 语法 | 函数调用形式 Object.assign(target, ...sources) | 语法糖,更简洁 { ...source } |
| 目标对象 | 可以指定任意目标对象(包括已存在的对象),会修改目标对象 | 总是创建一个新对象,不修改原对象 |
| 可读性 | 稍显冗长 | 更简洁、直观 |
| 继承属性 | 不会复制继承的属性(只复制自身可枚举属性) | 同上 |
| Symbol 属性 | 会复制 Symbol 类型的键名属性 | 会复制 Symbol 类型的键名属性 |
null/undefined 源对象 | 如果源为 null 或 undefined,会被忽略 | 如果源为 null 或 undefined,会被忽略(不报错) |
| 非对象源 | 会尝试将其转换为对象(如字符串、数字等) | 在对象字面量中使用时,非对象会报错或被忽略(取决于环境) |
关键区别示例:
const target = { x: 1 };
const source = { y: 2 };
// Object.assign 会修改 target
Object.assign(target, source);
console.log(target); // { x: 1, y: 2 } ← target 被修改了!
// 扩展运算符总是创建新对象
const newTarget = { ...target, ...source };
console.log(target); // { x: 1, y: 2 } (已被上面修改)
console.log(newTarget); // { x: 1, y: 2 } ← 新对象
3. 都是浅拷贝
两者都是浅拷贝,这意味着:
- 基本类型值(如字符串、数字)会被复制。
- 引用类型值(如对象、数组)只会复制其引用,而不是创建新对象。
const original = {
a: 1,
nested: { b: 2 }
};
// 浅拷贝
const copy = { ...original };
copy.nested.b = 3;
console.log(original.nested.b); // 3 ← 原对象也被修改了!
4. 如何实现深拷贝?
浅拷贝在处理嵌套对象时会有副作用。实现深拷贝的常见方法:
JSON.parse(JSON.stringify(obj)):简单但有局限(不能处理函数、undefined、Symbol、循环引用等)。- 递归遍历:手动实现深拷贝逻辑。
- 使用库:如 Lodash 的
_.cloneDeep()。
总结
| 问题 | 回答 |
|---|---|
| 区别 | Object.assign 可修改目标对象,扩展运算符总返回新对象;语法和使用习惯不同。 |
| 深拷贝 or 浅拷贝? | 都是浅拷贝。嵌套对象的属性是引用复制,修改会影响原对象。 |
建议:
- 优先使用对象扩展运算符,语法更现代、简洁。
- 若需修改已有对象,可用
Object.assign。 - 需要深拷贝时,应使用专门的深拷贝方法或库。
THE END


