JavaScript中扩展运算符(...)可简洁实现数组和对象的浅拷贝,但仅复制第一层属性;深层嵌套对象或数组仍共享引用,修改会影响原数据。

JavaScript 中用扩展运算符(...)做浅拷贝,是最简洁常用的方式之一,适用于数组和对象,但要注意它只复制第一层属性。
复制数组:展开后重新组装
扩展运算符把数组的每个元素“摊开”,再放进新数组里,生成一个新引用,原数组不受影响。
- 写法:
[...originalArray] - 修改新数组不会影响原数组(如 push、pop、赋值某索引)
- 但如果原数组里有对象或嵌套数组,这些嵌套内容仍是共享引用
例如:
const arr1 = [1, { name: 'Alice' }];const arr2 = [...arr1];
arr2[0] = 99; // 只改 arr2,arr1[0] 还是 1
arr2[1].name = 'Bob'; // arr1[1].name 也变成 'Bob' —— 浅拷贝的典型表现
复制对象:展开属性到新对象
对对象使用扩展运算符,会把可枚举的自有属性(不含原型链上的)复制到新对象中,生成一个独立的对象实例。
立即学习“Java免费学习笔记(深入)”;
- 写法:
{ ...originalObject } - 新对象与原对象引用不同,直接属性赋值互不影响
- 嵌套对象、数组等仍为引用共享,深层修改会同步
例如:
const obj1 = { a: 1, user: { id: 101 } };const obj2 = { ...obj1 };
obj2.a = 99; // obj1.a 不变
obj2.user.id = 202; // obj1.user.id 也变成 202
注意事项与常见误区
扩展运算符本质是浅拷贝,不是万能复制工具。以下情况需特别留意:
- 不能拷贝不可枚举属性(如
Object.defineProperty设置的enumerable: false属性) - 不处理
Symbol键(除非显式展开:{ ...obj, ...Object.getOwnPropertySymbols(obj).reduce((a, s) => ({ ...a, [s]: obj[s] }), {}) }) - 遇到
null或undefined会报错,需提前判断 - 类数组对象(如
arguments、NodeList)需先转成数组再展开,或用Array.from()配合
对比其他浅拷贝方式
扩展运算符和 Array.from()、Object.assign() 效果类似,都是浅拷贝:
-
[...arr]≈Array.from(arr)≈arr.slice()(仅数组) -
{ ...obj }≈Object.assign({}, obj) - 扩展运算符更直观、可读性更好,且支持在解构/合并时灵活组合(如
{ ...a, ...b, c: 3 })


















