概念与要点
- 解构赋值 是 ES6 引入的语法糖,用于按"模式匹配"从数组 或对象中提取值并赋给变量,能显著简化取值与传参代码。
- 数组解构按位置 匹配;对象解构按属性名匹配,顺序无关。
- 可配合默认值 、剩余元素 ... 、重命名 与嵌套解构使用。
- 右侧不是可迭代对象(数组解构)或右侧为 null/undefined(对象解构)会报错,需要做好容错处理。
数组解构
- 基本用法
- 按顺序取值:
const [a, b] = [1, 2]; // a=1, b=2
- 按顺序取值:
- 跳过元素
- 使用逗号占位:
const [a, , c] = [1, 2, 3]; // a=1, c=3
- 使用逗号占位:
- 默认值
- 仅当值为 undefined 时生效:
const [x=10, y=20] = [5]; // x=5, y=20;注意null不会触发默认值。
- 仅当值为 undefined 时生效:
- 剩余元素
- 收集剩余项:
const [head, ...tail] = [1,2,3,4]; // head=1, tail=[2,3,4]
- 收集剩余项:
- 可迭代性
- 右侧只要是可迭代对象 即可:
let [a,b,c] = 'abc'; // a='a',b='b',c='c';let [x,y] = new Set([1,2]);
- 右侧只要是可迭代对象 即可:
- 交换变量
- 一行交换:
[a, b] = [b, a];
- 一行交换:
- 常见陷阱
- 右侧非可迭代会报错:
let [foo] = 1; // TypeError。
- 右侧非可迭代会报错:
对象解构
- 基本用法
- 按属性名取值:
const {name, age} = {name:'Alice', age:25}; // name='Alice', age=25
- 按属性名取值:
- 重命名
- 将属性映射到新变量:
const {name: fullName, age: years} = user;
- 将属性映射到新变量:
- 默认值
- 属性缺失或值为 undefined 时使用:
const {theme='dark', lang='en'} = settings;
- 属性缺失或值为 undefined 时使用:
- 剩余属性
- 收集其余属性:
const {a, ...rest} = {a:1,b:2,c:3}; // rest={b:2,c:3}
- 收集其余属性:
- 嵌套解构
- 与数组/对象混合:
const {user:{name}, posts:[first]} = data;
- 与数组/对象混合:
- 常见陷阱
- 右侧为 null/undefined 会报错:
const {x} = null; // TypeError;可用空对象兜底:const {x} = maybeObj || {}; - 解构到已声明变量需加括号:
let x; ({x} = {x:1});。
- 右侧为 null/undefined 会报错:
函数参数解构
- 数组参数
- 直接解构参数:
function sum([a,b]) { return a+b; } sum([1,2]); // 3
- 直接解构参数:
- 对象参数
- 命名参数更清晰:
function greet({name, age}) { ... } greet({name:'Bob',age:30});
- 命名参数更清晰:
- 默认值与空对象兜底
- 同时给"参数对象"和"属性"默认值更安全:
function greet({name='Guest', age=0} = {}) { ... }- 调用:
greet(); // name='Guest', age=0;greet({name:'Tom'}); // age=0
常见用法与最佳实践
- 同时给"参数对象"和"属性"默认值更安全:
- 交换变量:
[a, b] = [b, a]; - 从函数返回多值:
function getUser(){ return {name:'Tom', age:30}; } const {name, age} = getUser();
- 处理 API 响应:
fetch('/api').then(r=>r.json()).then(({id, name, email})=>{ ... });
- 遍历键和值:
for (const [k, v] of Object.entries(obj)) { ... }
- 容错与兜底:
- 对象解构前:
const {a=1, b=2} = maybeObj || {}; - 深度解构前确保中间层级存在:
const {user: {profile: {city=''}}} = data ?? {};
- 对象解构前:
- 可迭代与字符串:
const [a,b] = 'hi'; // a='h', b='i';const {length} = 'abc'; // length=3
- 易错点速记:
- 数组解构依赖顺序;对象解构依赖属性名。
- 默认值仅在值为 undefined 时生效(
null不触发)。 - 右侧需可迭代(数组解构);对象解构右侧不可为 null/undefined。
- 已声明变量做对象解构需加括号:
({x}=obj);。
先声明变量再解构赋值的正确写法
数组解构 先声明后赋值
- 先声明变量,再用解构给已声明变量赋值,语法为:
[a, b] = 右侧可迭代对象;。右侧必须是可迭代对象(如数组、字符串、Set、Map 等)。 - 支持默认值 :
[x=10, y=20] = [5]; // x=5, y=20。 - 支持剩余元素 :
[head, ...tail] = [1,2,3]; // tail=[2,3];注意剩余元素必须是最后一个。 - 常见用途:一行交换变量 :
[a, b] = [b, a];。 - 易错点:右侧为 null/undefined 会抛出错误(数组解构要求右侧可迭代)。
对象解构 先声明后赋值
- 先声明变量,再用解构给已声明变量赋值,语法为:
({ a, b } = 对象);。由于{...}会被解析为代码块,必须用小括号 包裹:({ a, b } = obj);。 - 支持重命名 :
({ name: fullName, age: years } = user);。 - 支持默认值 :
({ theme='dark', lang='en' } = settings);;仅当属性值为 undefined 时生效(null不触发默认值)。 - 支持剩余属性 :
({ a, ...rest } = {a:1,b:2,c:3}); // rest={b:2,c:3}。 - 易错点:右侧为 null/undefined 会抛出错误;已声明变量做对象解构必须加括号。
常见陷阱与最佳实践
- 右侧合法性:数组解构右侧必须可迭代 ;对象解构右侧不能为 null/undefined 。不确定时可兜底:
const [a] = maybeArr || [];、const {x} = maybeObj || {};。 - 分号与括号:对象无声明解构必须加括号 ;若上一行以
[或(结尾,需在行首加分号以避免被当作上一行表达式继续解析:;[a, b] = [1, 2];。 - 默认值生效条件:仅在值为 undefined 时生效(
null不会触发默认值)。 - 剩余元素位置:...rest 必须是解构模式的最后一项,否则语法错误。
速查示例
js
// 数组:先声明后赋值
let a, b, rest;
[a, b] = [1, 2]; // a=1, b=2
[a, b = 10] = [5]; // a=5, b=10(默认值)
[a, ...rest] = [1,2,3]; // rest=[2,3]
[a, b] = [b, a]; // 交换:a=2, b=1
// 对象:先声明后赋值(注意小括号)
let x, y, z;
({ x, y } = { x: 1, y: 2 }); // x=1, y=2
({ x: foo, y: bar } = { x: 1, y: 2 }); // foo=1, bar=2
({ x = 10, y = 20 } = { x: 5 }); // x=5, y=20(默认值)
({ a, ...rest } = { a: 1, b: 2, c: 3 }); // rest={b:2,c:3}
对象为什么要使用小括号
{在语句开头会被解析为代码块,加 () 将其转为合法的表达式上下文
将对象字面量作为表达式使用场景
箭头函数直接返回对象:const f = () => ({ name: 'Tom' });
立即调用函数表达式:(function(){ /* ... */ })();
作为对象属性:const o = { data: ({ id: 1 }) };