混淆点
... 不是一个固定语法,本身也不代表"某个功能",它是一种语法标记。
决定它是展开(spread)还是剩余(rest)的,是它出现的位置和上下文。
...something
1 Spread 展开
2 Rest 收集Spread 展开 把"一个整体"拆开
用在数组字面量、函数调用参数、对象字面量中,作用是把一个可迭代对象(数组、字符串、Map/Set等)或对象"摊开"成一个个独立的元素。
// 1. 数组展开:把一个数组拆成散开的元素
const arr1 = [1, 2, 3];
const arr2 = [0, ...arr1, 4]; // [0, 1, 2, 3, 4]
// 2. 函数调用时展开:把数组拆成一个个参数
function sum(a, b, c) { return a + b + c; }
sum(...[1, 2, 3]); // 等价于 sum(1, 2, 3)
// 3. 对象展开(ES2018):把对象的键值对铺开合并
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// 4. 常见实战用法:浅拷贝、合并
const copy = [...arr1]; // 数组浅拷贝
const merged = { ...obj1, ...obj2 }; // 对象合并(后面覆盖前面)对象的处理:
cosnt user = {
name: "Ocean",
age: 18,
}
const newUser = {
...user,
gender: "male",
}
// 相当于
const finalUser = {
name: "Ocean",
age: 18,
gender: "male",
}spread 永远发生在"构造一个新东西"的时候(新数组、新对象、函数调用),它在消费/使用已有的数据。
Rest Parameters 剩余参数,收集剩余函数参数
用在函数参数列表中,把没有被显式命名的参数收集成一个数组。必须是最后一个参数。
function myFunc(first, second, ...rest) {
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
}
myFunc(1, 2, 3, 4, 5);
// 常见实战:替代 arguments 对象,写法更现代
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}Rest in Destructuring 剩余模式,解构时收集"剩下的"
用在解构赋值(数组解构 / 对象解构)的左边,把没被取走的部分收集起来。其实是"剩余参数"概念在解构场景里的延伸,所以也叫 rest。
// 数组解构 + rest
const [first, second, ...others] = [1, 2, 3, 4, 5];
// first = 1, second = 2, others = [3, 4, 5]
// 对象解构 + rest
const { a, b, ...restObj } = { a: 1, b: 2, c: 3, d: 4 };
// a = 1, b = 2, restObj = { c: 3, d: 4 }
// 实战:常用于过滤掉某些属性
function omitPassword(user) {
const { password, ...safeUser } = user;
return safeUser; // 返回不含 password 的对象
}区别
| 名称 | 出现位置 | 作用 | 方向 |
|---|---|---|---|
| Spread(展开) | 数组/对象字面量中、函数调用的参数中 | 把一个整体拆成多个元素 | 一 → 多(读取时) |
| Rest(剩余参数) | 函数定义的参数列表末尾 | 把多个实参收集成一个数组 | 多 → 一(定义时) |
| Rest(剩余解构) | 解构赋值的左边末尾 | 把解构后剩下的部分收集成一个新对象/数组 | 多 → 一(赋值时) |
问一个问题:这段代码是在"造"一个新数组/对象,还是在"拆"一个已有的东西?
- 如果代码是
[...x]、{...x}、f(...x)—— 这是在用 x 的内容去构造别的东西 → spread - 如果代码是
function f(...x)、const [a, ...x] = arr—— 这是在定义一种接收模式,把"剩下的东西"装进 x → rest
换句话说:spread 在"值"的位置上,rest 在"变量声明/参数声明"的位置上。