面试题:Object.assign 和对象扩展运算符有什么区别?是深拷贝还是浅拷贝?

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 源对象如果源为 nullundefined,会被忽略如果源为 nullundefined,会被忽略(不报错)
非对象源会尝试将其转换为对象(如字符串、数字等)在对象字面量中使用时,非对象会报错或被忽略(取决于环境)

关键区别示例:

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
喜欢就支持一下吧
点赞15 分享