扩展运算符...用于对象时实现浅拷贝与属性合并,只遍历自身可枚举属性、不递归、不处理getter/setter,不能展开null/undefined;等价于Object.assign({}, obj),但更简洁灵活。

扩展运算符 ... 在 JavaScript 中用于对象时,本质是将对象的可枚举自有属性(不包括原型链上的属性)逐个展开,生成新对象。它天然支持浅拷贝和属性合并,但要注意其行为边界——只处理一层,不递归。
用 ... 实现对象浅拷贝
对一个对象使用扩展运算符,会创建一个新对象,并把原对象所有可枚举自有属性复制过去。原对象与新对象内存地址不同,修改新对象的顶层属性不会影响原对象(但嵌套对象仍共享引用)。
示例:
const original = { a: 1, b: { c: 2 } };
const copy = { ...original };
copy.a = 99; // ✅ 不影响 original.a
copy.b.c = 99; // ❌ 会影响 original.b.c(b 是引用)
console.log(original); // { a: 1, b: { c: 99 } }
用 ... 合并多个对象
多个对象按顺序展开时,后出现的对象属性会覆盖前面同名属性。合并结果是一个全新对象,原对象均不受影响。
常见写法:
- 基础合并:
{ ...obj1, ...obj2 } - 添加新属性:
{ ...obj, newKey: newValue } - 覆盖特定字段:
{ ...obj, id: 100, name: 'updated' }
注意:如果多个对象有相同键,右边的值生效;undefined 不会覆盖已有值,但 null、0、false 等假值会正常覆盖。
注意事项与常见陷阱
扩展运算符不是万能的,需留意以下限制:
-
只遍历自身可枚举属性:不会拷贝原型上的方法或
Symbol属性(除非显式列出) - 不处理 getter/setter:若属性是 getter,展开后得到的是其返回值,而非 getter 函数本身
- 不能替代深拷贝:嵌套对象、数组、日期、正则等复杂类型仍为引用
-
不能展开 null 或 undefined:会报错
TypeError: Cannot spread non-iterable instance
安全做法:合并前做空值判断,例如 { ...(obj || {}), ...other }。
对比其他浅拷贝方式
扩展运算符效果等价于 Object.assign({}, obj),但更简洁、可读性更强,且支持在字面量中灵活插入/覆盖字段。相比 JSON.parse(JSON.stringify(obj)),它不丢函数、undefined、Symbol、循环引用等问题,但也不支持深拷贝。
简单说:要浅拷贝或合并,优先用 ...;要深拷贝,得借助结构化克隆(structuredClone)或第三方库。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











