Rest用于收拢参数或解构左侧,Spread用于展开数组/对象或解构右侧;Rest必在参数末尾且唯一,Spread可多处使用;二者语法相同但语义相反,上下文决定行为。

Rest 和 Spread 都用 ...,但作用完全相反:Rest 是“收”,Spread 是“放”。记错位置或场景,轻则报错,重则逻辑静默失效。
函数参数里出现的 ... 一定是 Rest 参数
它只出现在函数定义的参数列表末尾,把所有“多出来的”实参打包成一个真数组——不是类数组的 arguments,能直接调 .map()、.filter()。
- 必须是最后一个参数,写在前面会报
SyntaxError: Rest parameter must be last formal parameter - 只能有一个,重复写
function f(...a, ...b)直接语法错误 - 和固定参数混用时,固定参数按顺序先匹配,剩下全归 Rest:
function log(first, ...rest) { console.log('首项:', first); // 'a' console.log('其余:', rest); // ['b', 'c'] } log('a', 'b', 'c');
函数调用、数组/对象字面量中出现的 ... 一定是 Spread 运算符
它把一个可迭代值(数组、字符串、Set)或对象“摊开”,把每个元素/属性逐个注入到新结构中。
- 函数调用时展开数组传参:
Math.max(...[1, 5, 3])✅;Math.max([1, 5, 3])❌(结果是NaN) - 合并数组:
const arr = [...arr1, ...arr2]—— 不是[arr1, arr2](那会嵌套) - 对象浅拷贝+覆盖:
const user = { name: 'Alice', age: 30 }; const updated = { ...user, age: 31, city: 'Beijing' }; // { name: 'Alice', age: 31, city: 'Beijing' } - 注意:Spread 对对象只做一层展开,深层嵌套仍是引用(不是深拷贝)
解构赋值中,... 的角色取决于它在等号左边还是右边
这是最容易混淆的点:同一符号,在解构左侧是 Rest,在右侧是 Spread。
立即学习“Java免费学习笔记(深入)”;
- 左侧(接收端)→ Rest:
const [a, b, ...rest] = [1, 2, 3, 4]→rest是[3, 4] - 右侧(提供端)→ Spread:
const nums = [2, 3]; const all = [1, ...nums, 4]→[1, 2, 3, 4] - 对象解构同理:
const { id, ...data } = { id: 1, name: 'x', role: 'admin' }→data是{ name: 'x', role: 'admin' }
真正卡住人的往往不是语法,而是没意识到 ... 的行为完全由它所处的上下文决定:参数定义?→ Rest;调用/字面量/解构右侧?→ Spread;解构左侧?→ Rest。写错位置,JS 解析器不会猜你意图,只会报错或产出意外结果。











