一、解构赋值(Destructuring Assignment)
作用:按模式从数组或对象中提取值,并赋给变量。
1. 数组解构
按位置匹配:
js
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3
// 跳过元素
const [, , third] = arr;
console.log(third); // 3
// 默认值
const [x, y = 10] = [5];
console.log(x, y); // 5 10
// 嵌套解构
const [i, [j, k]] = [1, [2, 3]];
console.log(i, j, k); // 1 2 3
2. 对象解构
按属性名匹配,顺序无关:
js
const user = { name: 'Alice', age: 25 };
const { name, age } = user;
console.log(name, age); // 'Alice' 25
// 重命名
const { name: userName, age: userAge } = user;
console.log(userName); // 'Alice'
// 默认值
const { role = 'user' } = user;
console.log(role); // 'user'
// 嵌套解构
const person = {
name: 'Bob',
address: { city: 'Beijing' }
};
const { address: { city } } = person;
console.log(city); // 'Beijing'
3. 函数参数解构
直接提取形参:
js
function greet({ name, age }) {
console.log(`${name} is ${age}`);
}
greet({ name: 'Tom', age: 30 }); // Tom is 30
// 配合默认值
function draw({ x = 0, y = 0 } = {}) {
console.log(x, y);
}
draw(); // 0 0
4. 用途场景
- 交换变量 :
[a, b] = [b, a]; - 提取 JSON 数据 、import 具名导出等。
- 解析函数返回值:
js
function getInfo() {
return { status: 200, data: [1,2] };
}
const { status, data } = getInfo();
二、扩展运算符(Spread Operator)
语法 :... 在可迭代对象 (数组、字符串等)或对象前使用,将其展开为单独元素。
1. 数组扩展
js
// 复制数组(浅拷贝)
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
// 合并数组
const arr3 = [...arr1, 4, 5];
console.log(arr3); // [1,2,3,4,5]
// 将类数组/可迭代对象转为真数组
const nodeList = document.querySelectorAll('div');
const divArray = [...nodeList];
// 与解构结合(剩余属性在解构中也是 ...)
const [first, ...rest] = [10, 20, 30];
console.log(rest); // [20, 30]
2. 对象扩展
js
// 浅拷贝对象
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1 };
// 合并对象,同名属性后者覆盖前者
const merged = { ...obj1, c: 3, a: 99 };
console.log(merged); // { a: 99, b: 2, c: 3 }
// 用于为对象添加属性(不可变更新)
const newUser = { ...oldUser, age: 26 };
3. 函数调用扩展
将数组展开为独立参数:
js
const nums = [5, 2, 9];
Math.max(...nums); // 相当于 Math.max(5, 2, 9)
// 与普通参数混用
function sum(a, b, c) { return a + b + c; }
sum(...[1, 2, 3]); // 6
4. 注意事项
- 扩展运算符执行的是浅拷贝,嵌套对象仍共享引用。
- 对于对象扩展,是 ES2018 引入,与数组扩展的
...语法相同但语义不同(对象扩展不是迭代行为,而是枚举自身可枚举属性)。
三、剩余参数(Rest Parameters)
语法 :... 在函数声明或解构赋值中,将剩余元素收集为一个数组。
1. 函数剩余参数
将不定数量的参数收集为数组,替代 arguments:
js
function logAll(...args) {
console.log(args); // 真数组,可使用 map、filter 等
}
logAll(1, 'a', true); // [1, 'a', true]
// 收集剩余参数
function multiply(factor, ...nums) {
return nums.map(n => n * factor);
}
multiply(2, 1, 2, 3); // [2, 4, 6]
注意:
- 剩余参数必须是函数的最后一个参数。
- 箭头函数没有
arguments,必须用剩余参数。
2. 解构中的剩余模式
收集数组/对象中未被提取的部分:
js
// 数组剩余
const [head, ...tail] = [1, 2, 3, 4];
console.log(tail); // [2, 3, 4]
// 对象剩余
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(rest); // { c: 3, d: 4 }
对象剩余属性也是浅拷贝,并只收集自身的可枚举属性。
四、三者对比与关键区别
| 特性 | 解构赋值 | 扩展运算符 | 剩余参数 |
|---|---|---|---|
| 作用 | 拆分数据为变量 | 展开数据为元素 | 收集元素为数组 |
| 语法位置 | 赋值表达式的左边 | 字面量或函数调用的右边 | 函数参数或解构赋值左边 |
| 典型语法 | const { x } = obj |
[...arr], {...obj} |
function(...args) |
| 运作方向 | 分解 | 展开 | 聚集 |
| 返回值 | 变量 | 新的数组/对象 | 数组 |
五、综合示例:解构 + 扩展 + 剩余参数
js
const obj = { x: 1, y: 2, z: 3, w: 4 };
const { x, ...others } = obj; // 解构 + 剩余
console.log(others); // { y: 2, z: 3, w: 4 }
const newObj = { ...others, x: 10 }; // 扩展,覆盖 x
console.log(newObj); // { y: 2, z: 3, w: 4, x: 10 }
function process(first, ...rest) {
const combined = [first, ...rest.map(v => v * 2)]; // 扩展
return combined;
}
console.log(process(5, 1, 2, 3)); // [5, 2, 4, 6]