同学们好,我是 Eugene(尤金),一个拥有多年中后台开发经验的前端工程师~
(Eugene 发音很简单,/juːˈdʒiːn/,大家怎么顺口怎么叫就好)
你是否也有过:明明学过很多技术,一到关键时候却讲不出来、甚至写不出来?
你是否也曾怀疑自己,是不是太笨了,明明感觉会,却总差一口气?
就算想沉下心从头梳理,可工作那么忙,回家还要陪伴家人。
一天只有24小时,时间永远不够用,常常感到力不从心。
技术行业,本就是逆水行舟,不进则退。
如果你也有同样的困扰,别慌。
从现在开始,跟着我一起心态归零,利用碎片时间,来一次彻彻底底的基础扫盲。
这一次,我们一起慢慢来,扎扎实实变强。
不搞花里胡哨的理论堆砌,只分享看得懂、用得上的前端干货,
咱们一起稳步积累,真正摆脱“面向搜索引擎写代码”的尴尬。
前言
后台接口返回的数据,常常是嵌套对象或数组,很多人习惯一层层 data.user.name 这样写,既啰嗦又容易在某一层是 undefined 时直接报错。
用解构赋值 + 默认值,可以把取数写得又短又安全。本文用 10 个常见写法,帮你把「接口数据解包」这件事理清楚。
适合读者:
- 已经会写 JS,但对解构、默认值组合用法不熟
- 刚学 JS,希望一开始就养成规范写法
- 有一定经验,想统一团队里的接口数据处理方式
一、先搞清楚:解构在干什么
解构不是黑魔法,本质是按结构从对象/数组中「拆包」出变量,语法更短,逻辑更直观。
// 传统写法:手动挨个取值
const user = { name: '张三', age: 28, city: '北京' };
const name = user.name;
const age = user.age;
// 解构写法:一次性拆出来
const { name, age } = user;
如果接口返回的 user 某天变成 null,传统写法会在 user.name 直接报错,解构可以配合默认值一起用,后面会展开。
二、接口数据解包的 10 个常见写法
假设后台返回结构类似:
{
code: 200,
data: {
user: {
id: 1,
name: '李四',
profile: {
avatar: 'https://xxx/avatar.png',
bio: '前端工程师'
}
},
list: [
{ id: 1, title: '文章1' },
{ id: 2, title: '文章2' }
]
}
}
下面 10 个写法,都是日常会用到的。
写法 1:只解构第一层,其余用 rest 收走
const { user, list, ...rest } = response.data;
// user、list 单独用,其他字段在 rest 里
适用: 只需要其中几个字段,但不想丢掉其他字段。
注意: rest 不会包含已解构的 user、list。
写法 2:解构 + 默认值,防止 undefined
const { user = {}, list = [] } = response.data || {};
适用: 接口可能返回 data 为 null、undefined,或字段缺失。
注意: 默认值只在值为 undefined 时生效,null 不会触发默认值。
写法 3:多层嵌套一次解构
const { user: { profile: { avatar, bio } = {} } = {} } = response.data || {};
适用: 需要深层字段,不想写 data.user.profile.avatar。
踩坑: 每一层都要给默认值 = {},否则中间某层是 undefined 会报错。
写法 4:解构时重命名,避免变量冲突
const { user: currentUser, list: articleList } = response.data || {};
适用: 接口字段名不直观,或和已有变量重名。
语法: 原属性名: 新变量名。
写法 5:解构 + 默认值 + 重命名一起用
const { user: currentUser = {}, list: articleList = [] } = response.data || {};
适用: 既要改名,又要防缺。
推荐: 作为接口数据解包的常规写法,可读性和安全性都较好。
写法 6:数组解构取首项
const [firstItem] = response.data?.list || [];
适用: 列表只关心第一项(例如「最新一条」)。
注意: 用可选链 ?. 和 || [] 避免 list 为 null/undefined 时报错。
ps· 如果你不知道可选链请点击这里,一文让你轻松了解
写法 7:解构数组元素并设默认值
const [first = {}, second = {}] = response.data?.list || [];
适用: 需要前几项,且要保证拿到的一定是对象。
注意: 空数组时 first、second 都是 {}。
写法 8:在 map 中解构,简化遍历
const titles = (response.data?.list || []).map(({ id, title }) => title);
适用: 列表只需部分字段,不想写 item.id、item.title。
好处: 代码短,意图清晰。
写法 9:解构函数参数,配合默认值
function renderUser({ name = '游客', avatar = '/default.png' } = {}) {
// 函数内部直接用 name、avatar
}
renderUser(response.data?.user); // 即使传入 undefined 也不报错
适用: 组件、工具函数接收配置对象时。
双重默认值:
= {}:整个参数缺失时name = '游客':name缺失时
写法 10:安全取出深层字段的「一层层解构」写法
const { data } = response || {};
const { user } = data || {};
const { profile } = user || {};
const { avatar } = profile || {};
// 或者一行(每层都要默认值)
const avatar = ((response || {}).data || {}).user?.profile?.avatar ?? '默认头像';
适用: 接口结构不稳定,或经常变更。
建议: 优先用可选链 ?. 和空值合并 ??,逻辑更简洁。
三、容易踩的坑
1. 默认值只对 undefined 生效
const { name = '默认' } = { name: null };
// name 是 null,不是 '默认'
需要兼容 null 时,用空值合并运算符 ??:
const name = (obj.name ?? '默认');
2. 嵌套解构少了中间层的默认值
const { user: { profile } } = response.data; // 若 user 为 undefined,直接报错
const { user: { profile } = {} } = response.data; // 依然可能报错,user 本身可能 undefined
const { user: { profile } = {} } = response.data || {}; // 正确:两层都要有兜底
3. 解构赋值和变量声明混在一起
const obj = { a: 10 };
// ✅ 正确:声明+解构一步完成({}是声明语法的一部分,解析器认解构)
let {a} = obj;
let b;
// {b} = obj; // ❌ 报错:语句开头的{}被解析为“块级作用域”,而非解构
({b} = obj); // ✅ 正确:括号让{}变成表达式,解析器认解构
4. 把 rest 用在已解构过的属性上
const obj = { a: 1, b: 2, c: 3 };
// 解构:单独取出a,剩余属性打包到rest
const { a, ...rest } = obj;
console.log(a); // 输出:1(单独提取的a)
console.log(rest); // 输出:{ b: 2, c: 3 }(rest不含已解构的a)
四、实战推荐写法模板
通用接口解包:
const response = {
code: 200,
msg: "请求成功",
data: {
user: {
name: "张三",
age: 25,
profile: {
avatar: "https://example.com/avatar.jpg"
}
},
list: [
{ id: 1, title: "文章1", content: "内容1" },
{ id: 2, title: "文章2", content: "内容2" }
]
}
};
// 1. 最外层兜底:避免response/null/undefined导致解构报错
const { data = {} } = response || {};
// 2. 解构data层:给user/List设默认值,避免属性不存在
const { user = {}, list = [] } = data;
// 3. 深层解构user:给profile兜底,避免profile为undefined时报错
const { name, profile: { avatar } = {} } = user;
// 4. 列表解构:只提取需要的id/title,过滤无用字段
const items = list.map(({ id, title }) => ({ id, title }));
// 输出结果(验证解构效果)
console.log(name); // 张三
console.log(avatar); // https://example.com/avatar.jpg
console.log(items); // [{id:1,title:"文章1"}, {id:2,title:"文章2"}]
封装成工具函数:
function parseUserResponse(response) {
const { data: { user = {} } = {} } = response || {};
const { name = '未知', profile: { avatar = '/default.png' } = {} } = user;
return { name, avatar };
}
五、小结
| 场景 | 推荐写法 |
|---|---|
| 防缺 | const { a = {} } = obj || {} |
| 嵌套解构 | 每一层都写 = {} 兜底 |
| 需要改名 | const { a: newName } = obj |
| 取列表首项 | const [first] = list || [] |
| 列表 map | list.map(({ id, title }) => ...) |
| 函数参数 | ({ a = 1 } = {}) 双重默认值 |
记住一点:解构是语法糖,默认值是兜底,把两者结合起来,接口数据处理会干净很多,也更容易排查问题。
🔍 本系列专栏导航
一、《var/let/const:变量与作用域实战选型|JS 基础语法与数据操作篇》
二、《this、箭头函数与普通函数:前端实战避坑指南 | JS 基础语法与数据操作篇》
三、《对象解构赋值:接口数据解包 10 个实战写法|JS 基础语法与数据操作篇》
四、《map/filter/reduce:数组10个常用实战操作|JS 基础语法与数据操作篇》
五、《find/some/every/includes:数组查找与判断实战用法|JS 基础语法与数据操作篇》
六、《sort/localeCompare:对象数组排序与分组实战|JS 基础语法与数据操作篇》
七、《模板字符串 /split/join/ 正则:字符串处理实战|JS 基础语法与数据操作篇》
八、《Date/dayjs:日期时间处理实战|JS 基础语法与数据操作篇》
九、《try/catch/Promise:前端错误处理实战|JS 基础语法与数据操作篇》
十、《import/export:前端模块化实战|JS 基础语法与数据操作篇》
👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~
学习本就是一场持久战,不需要急着一口吃成胖子。哪怕今天你只记住了一点点,这都是实打实的进步。
后续我还会继续用这种大白话、讲实战方式,带大家扫盲更多前端基础。
关注我,不迷路,咱们把那些曾经模糊的知识点,一个个彻底搞清楚。
如果你觉得这篇内容对你有帮助,不妨点赞+收藏,下次写代码卡壳时,拿出来翻一翻,比搜引擎更靠谱。
我是 Eugene,你的电子学友,我们下一篇干货见~