展开语法...用于数组、对象、函数调用等场景,实现浅拷贝、合并、解构等功能,但不可单独使用,且对null/undefined会报错。

... 是 JavaScript 中用于“展开”可迭代对象(如数组、字符串、Map、Set)或对象属性的语法糖,不是运算符,也不能单独存在——它必须出现在数组字面量 [...arr]、对象字面量 {...obj} 或函数调用 func(...arr) 中。
合并数组时怎么避免嵌套?
常见错误是写成 [arr1, arr2],结果得到二维数组 [[1,2], [3,4]]。正确做法是加 ... 展开:
const arr1 = [1, 2]; const arr2 = [3, 4]; const merged = [...arr1, ...arr2]; // → [1, 2, 3, 4]
- 支持插入字面量:
[...arr1, 99, ...arr2] - 不修改原数组,返回新数组
- 若需去重合并,可结合
Set:[...new Set([...arr1, ...arr2])]
对象合并时同名属性谁生效?
对象展开按顺序覆盖:后写的属性会覆盖前面同名的值。
const defaults = { theme: 'light', lang: 'en' };
const userConfig = { theme: 'dark' };
const config = { ...defaults, ...userConfig }; // → { theme: 'dark', lang: 'en' }
- 适合配置项覆盖场景(如默认配置 + 用户覆盖)
- 仅浅合并:嵌套对象不会递归合并,
defaults.nested和userConfig.nested仍是独立引用 - 不能展开
null或undefined,否则报错;可用空值合并:{ ...(obj ?? {}) }
传参给函数时为什么不用 apply 了?
过去要写 Math.max.apply(null, arr),现在直接 Math.max(...arr) 更直观安全。
立即学习“Java免费学习笔记(深入)”;
const numbers = [7, 2, 9]; console.log(Math.max(...numbers)); // → 9 console.log(sum(...numbers)); // → 18(假设 sum(a,b,c) => a+b+c)
- 替代
func.apply(this, args)的标准写法 - 构造函数也适用:
new Date(...[2023, 0, 1]) - 注意:超大数组(>10万元素)可能触发栈溢出,此时应改用循环或
Math.max.apply(虽已过时但更耐扛)
复制和解构时要注意什么?
[...arr] 和 {...obj} 都是浅拷贝——只复制第一层,嵌套结构仍共享引用。
const original = { a: 1, b: { c: 2 } };
const copy = { ...original };
copy.b.c = 99;
console.log(original.b.c); // → 99(被意外改了!)
- 字符串也能展开:
[...'hi'] → ['h', 'i'],常用于字符遍历或去重 - 解构中配合剩余参数:
const [first, second, ...rest] = [1,2,3,4,5]; - 不能单独写
...arr,会语法错误;必须在[]、{}或()内
真正容易被忽略的是:它对 null、undefined、普通对象(非可迭代)直接展开会报错,而很多人只在开发环境试过“有值”的情况,上线后遇到空数据就崩。用之前先判空,比事后 debug 快得多。











