扩展运算符合并数组/对象均为浅拷贝,不递归处理嵌套,不支持null/undefined,大数组易栈溢出,需依场景选用concat、flat、Object.assign等替代方案。
[...array] 合并数组,但要注意浅拷贝和嵌套问题扩展运算符合并数组本质是展开后拼接,不是“深合并”。比如:
const a = [1, 2];看起来没问题,但若
const b = [3, [4, 5]];
const c = [...a, ...b]; // [1, 2, 3, [4, 5]]
b[3] 是个引用对象,修改它会同时影响原数组。常见误用是以为 [...a, ...b] 能递归扁平化——它不能,[...b] 只展开一层。
需要扁平化时得配合 flat():
const nested = [1, [2, 3], [4, [5]]];
const flatOnce = [...nested.flat(1)]; // [1, 2, 3, 4, [5]]
const deepFlat = [...nested.flat(Infinity)]; // [1, 2, 3, 4, 5]
[...a, ...b] 替代 a.concat(b) 来处理 null 或 undefined —— 会报 TypeError: undefined is not iterable
push.apply 或循环Array.from() 比扩展运算符更健壮,支持类数组(如 arguments、NodeList){...obj}
合并对象,同名属性会被后者覆盖对象扩展是浅拷贝+覆盖式合并,顺序决定优先级:
const a = { x: 1, y: 2 };
const b = { y: 3, z: 4 };
const merged = { ...a, ...b }; // { x: 1, y: 3, z: 4 }注意:...b 写在后面,它的 y 就会覆盖 a.y;反过来写就是 a 覆盖 b。
遇到嵌套对象,不会递归合并:
const a = { user: { name: 'A' } };
const b = { user: { age: 25 } };
const bad = { ...a, ...b }; // { user: { age: 25 } } ← a.user 整个被替换
Object.assign() 配合工具函数(如 Lodash 的 merge)...obj 会跳过原型链上的属性,只拷贝自身可枚举属性Object.defineProperty 设为 enumerable: false)会被丢弃常见错误是把数组当对象展开,或在对象中错误使用数组扩展:
const arr = [1, 2];
const obj = { a: 3 };
// ❌ 错误:试图把数组展开进对象字面量顶层
// { ...arr, ...obj } → 语法错误,因为 arr 展开后是 1, 2,不是键值对
// ✅ 正确:要么全数组,要么对象里包数组
const combinedArr = [...arr, obj]; // [1, 2, { a: 3 }]
const combinedObj = { ...obj, items: arr }; // { a: 3, items: [1, 2] }
[...arr] 作为属性值而不带键名——那只是表达式,不是合法属性定义['a','b'] → {a: true, b: true}),得用 Object.fromEntries() 配合 map,不能靠扩展运算符扩展运算符不是万能胶。遇到这些情况,换方法更稳:
// 大数组合并(避免栈溢出)
const bigA = new Array(200000).fill(1);
const bigB = new Array(200000).fill(2);
// ❌ 危险
// const huge = [...bigA, ...bigB];
// ✅ 安全
const huge = bigA.concat(bigB); // 或用 Array.prototype.push.apply([], ...)
undefined 元素时,Array.from({ length: 3 }) 比 [...Array(3)] 更可靠(后者生成三个 empty 槽位){...obj} 会执行 getter 并固化结果,丢失响应性;此时该用 Object.assign 或自定义克隆逻辑