扩展运算符(Spread ...)和剩余参数(Rest ...)的区别?
在 JavaScript 中,扩展运算符(Spread)和剩余参数(Rest)虽然长得一模一样,都是三个点(...),但它们的作用是完全相反的。
记住一句核心口诀:Rest 是“打包”(收集),Spread 是“解包”(展开)。
以下是它们的详细区别和使用场景:
一、 剩余参数(Rest Parameters)—— “打包”
作用: 把多个独立的元素,收集(打包)成一个数组或对象。
位置: 通常出现在赋值号的左侧,或者函数的形参(参数定义)中。
1. 用在函数的形参中
它用来代替传统的 arguments 对象,将传入的多余参数收集到一个真正的数组中。
javascript
// 这里的 ...numbers 是剩余参数
function sum(first, ...numbers) {
console.log(first); // 1
console.log(numbers); // [2, 3, 4] (被打包成了一个数组)
}
sum(1, 2, 3, 4);
⚠️ 注意:剩余参数必须是函数的最后一个参数。function (a, ...rest, b) 会报错。
2. 用在解构赋值中(数组/对象)
在提取数组或对象时,把剩下没被提取的属性/元素,收集到一个新数组或新对象里。
javascript
// 数组解构
const [a, b, ...restArray] = [10, 20, 30, 40, 50];
console.log(restArray); // [30, 40, 50]
// 对象解构
const user = { name: 'Alice', age: 25, city: 'New York', job: 'Dev' };
const { name, ...restObject } = user;
console.log(restObject); // { age: 25, city: 'New York', job: 'Dev' }
二、 扩展运算符(Spread Operator)—— “解包”
作用: 把一个可迭代对象(如数组、字符串)或对象,展开(解包)成一个个独立的元素或属性。
位置: 通常出现在赋值号的右侧,或者函数的实参(函数调用)中。
1. 用在函数调用时(传递实参)
把一个数组拆解成独立的参数传给函数。
javascript
const numbers = [1, 5, 8, 3];
// Math.max 不能直接接收数组,需要用 ... 把它展开
// 相当于 Math.max(1, 5, 8, 3)
const max = Math.max(...numbers);
console.log(max); // 8
2. 数组的合并与拷贝(浅拷贝)
javascript
const arr1 = [1, 2];
const arr2 = [3, 4];
// 合并数组
const merged = [...arr1, ...arr2, 5];
console.log(merged); // [1, 2, 3, 4, 5]
// 拷贝数组
const copyArr = [...arr1];
3. 对象的合并与拷贝(浅拷贝)
javascript
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3 };
// 合并对象
const mergedObj = { ...obj1, ...obj2, d: 4 };
console.log(mergedObj); // { a: 1, b: 2, c: 3, d: 4 }
// 拷贝对象
const copyObj = { ...obj1 };
4. 展开字符串
javascript
const str = "hello";
const chars = [...str];
console.log(chars); // ['h', 'e', 'l', 'l', 'o']
三、 核心对比总结表
| 对比维度 | 剩余参数(Rest ...) |
扩展运算符(Spread ...) |
|---|---|---|
| 核心动作 | 收集/打包 (Gather / Pack) | 展开/解包 (Spread / Unpack) |
| 数据变化 | 多个元素 1个数组/对象 | 1个数组/对象 多个元素/属性 |
| 出现位置 | 函数定义(形参)、解构赋值(左侧) | 函数调用(实参)、数组/对象字面量(右侧) |
| 通俗理解 | “剩下的全都装进这个篮子里” | “把这个篮子里的东西全倒出来” |
| 代码示例 | function f(a, ...rest) {} const [a, ...rest] = arr; |
f(...arr); const newArr = [...arr1]; |
终极判断技巧:
如果你看到 ... 是在定义变量(如函数参数定义、解构),那就是 Rest(剩余参数)。
如果你看到 ... 是在使用已有变量(如传参给函数、构建新数组/对象),那就是 Spread(扩展运算符)。