在合并对象或复制属性时,Object.assign()和扩展运算符...是JavaScript中最常用的两个工具。它们都执行浅拷贝,但在语法、行为细节和适用场景上存在一些值得注意的差异。
![图片[1]-Object.assign()和扩展运算符…有什么区别?-速码派](http://www.sumapai.com/wp-content/uploads/2026/01/528f9780d6684f47b199d3a3bfd61de5tplv-tb4s082cfz-aigc_resize_1080_1080-1.webp)
基本语法与使用方式
Object.assign()是一个方法调用,它将一个或多个源对象的可枚举自身属性复制到目标对象,并返回修改后的目标对象。
const target = { a: 1 };
const source = { b: 2 };
const result = Object.assign(target, source);
console.log(target); // { a: 1, b: 2 }
console.log(result === target); // true
它会修改第一个参数(目标对象)。为了避免这种情况,通常将空对象{}作为第一个参数。
扩展运算符...则是一种更直观的表达式语法。它在字面量对象或数组内部使用,将源对象的所有可枚举自身属性“展开”到当前位置。
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 2 }
这种方式直接创建了一个新对象,不会修改任何现有对象,更符合函数式编程中不可变性的思想。
对Getter/Setter的复制行为
一个关键区别在于它们如何处理源对象中的属性描述符。Object.assign()在复制属性时,会将源对象属性的值(即调用Getter后的结果)赋给目标对象。
const source = {
get value() { return 42; }
};
const target = {};
Object.assign(target, source);
console.log(Object.getOwnPropertyDescriptor(target, 'value'));
// { value: 42, writable: true, enumerable: true, configurable: true }
属性被复制后,target.value变成了一个普通的数据属性(值为42),原先的Getter被“执行并扁平化”了。
扩展运算符在复制时,行为与Object.assign()一致,也是复制Getter执行后的值,而不是Getter本身。
const copy = { ...source };
console.log(Object.getOwnPropertyDescriptor(copy, 'value'));
// 结果同上,也是一个值为42的普通数据属性
因此,两者都无法保留源对象中属性的Getter/Setter特性,如果需要完整复制属性描述符,需要使用Object.getOwnPropertyDescriptor和Object.defineProperty。
拷贝属性的完整性与原型链
Object.assign()只复制对象自身的可枚举属性。它忽略不可枚举属性和继承自原型链的属性。
扩展运算符的行为完全相同,也只复制源对象自身的可枚举属性。
一个细微差别是,Object.assign()会触发目标对象上的Setter,而扩展运算符在构建新对象时不会触发任何Setter,因为它是在直接定义新属性。
在实际开发中,扩展运算符因其简洁的语法和不可变的特性,在创建新对象、合并配置或更新状态时更为常用。Object.assign()则在需要明确指定目标对象,或在不支持扩展运算符的旧环境中使用。两者都是浅拷贝,对于嵌套对象都需要谨慎处理。




















暂无评论内容