前言
后台接口返回的数据,常常是嵌套对象或数组,很多人习惯一层层 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 } = {}) 双重默认值 |
记住一点:解构是语法糖,默认值是兜底,把两者结合起来,接口数据处理会干净很多,也更容易排查问题。
以上就是本次的学习分享,欢迎大家在评论区讨论指正,与大家共勉。
我是 Eugene,你的电子学友。
如果文章对你有帮助,别忘了点赞、收藏、加关注,你的认可是我持续输出的最大动力~