嵌套对象与数组
这是什么:嵌套 = 数据套数据:对象里装数组、数组里装对象,一层层像俄罗斯套娃。真实接口返回的数据全是这种结构。
为什么用:接口返回的「用户列表」「商品列表」都是「数组套对象」,不会拆嵌套就拿不到数据;而且套得越深,取值越容易踩 undefined 的坑。
如何用:先学「一层层点下去」的取值,再学 for 循环遍历,最后用 ?. 可选链防报错。
多层取值:一路点下去
let data = {
class: '蛙一班',
teacher: { name: '蛙老师', room: 'B201' },
students: [
{ name: '呱小吉', age: 3 },
{ name: '蛙大壮', age: 4 }
]
}
console.log(data.teacher.name) // 蛙老师(对象点对象)
console.log(data.students[0].name) // 呱小吉(数组先按下标,再点属性)
console.log(data.students[1].age) // 4
「你会看到」:规律就一句话——对象用 . 点属性,数组用 [下标] 取元素,从外往内一层层拆。
| 表达式 | 读法 | 结果 |
|---|---|---|
data.class |
data 的 class | '蛙一班' |
data.teacher.room |
data 的 teacher 的 room | 'B201' |
data.students[0] |
students 里的第 0 个 | 呱小吉那个对象 |
data.students[0].name |
第 0 个学生的名字 | '呱小吉' |
遍历对象数组:for...of
拿到一个「学生列表」,最常用 for...of 逐个处理:
for (let stu of data.students) {
console.log(`${stu.name} 今年 ${stu.age} 岁`)
}
你会看到:
呱小吉 今年 3 岁
蛙大壮 今年 4 岁
stu 依次是数组里的每个对象,循环体里正常点属性取值。要筛选就配 filter,要加工就配 map:
let names = data.students.map(stu => stu.name)
console.log(names) // ['呱小吉', '蛙大壮']
遍历纯对象:Object.keys / Object.entries
for...of 只能遍历数组。想遍历对象的每个键值对,先把它变成数组:
let frog = { name: '呱小吉', age: 3, skill: '游泳' }
console.log(Object.keys(frog)) // ['name', 'age', 'skill']
for (let [key, value] of Object.entries(frog)) {
console.log(`${key}: ${value}`)
}
你会看到:
name: 呱小吉
age: 3
skill: 游泳
Object.keys 拿所有键名,Object.entries 拿所有「键值对」——配置项打印、调试数据时特别好用。
?. 可选链:缺了也不报错
从深层取值最大的风险:中间某一层不存在,继续点就炸:
let user = { name: '呱小吉' } // 注意:没有 address 这个键
console.log(user.address.city) // ❌ TypeError: Cannot read properties of undefined
console.log(user.address?.city) // ✅ undefined,不报错
?. 的意思是「这一层存在才继续往下取,不存在就返回 undefined」。接口数据不保证字段齐全,读深层字段时用 ?. 是最省心的防错手段(user?.address?.city 连第一层也能防)。
记忆口诀:对象点、数组下标,一层一层往里瞧;中间可能缺一环,问号点防摔跤。
📦 完整小示例
一份班级成绩单,统计平均分并找出最高分:
let report = {
class: '蛙一班',
scores: [
{ name: '呱小吉', score: 92 },
{ name: '蛙大壮', score: 85 },
{ name: '蛙萌萌', score: 98 }
]
}
let list = report.scores
let total = 0
let best = list[0]
for (let stu of list) {
total = total + stu.score
if (stu.score > best.score) {
best = stu
}
}
console.log(`${report.class} 共 ${list.length} 人,平均分 ${total / list.length}`)
console.log(`最高分:${best.name} ${best.score} 分`)
你会看到:
蛙一班 共 3 人,平均分 91.66666666666667
最高分:蛙萌萌 98 分
逐段中文精讲
- 第 2~10 行(数据区):对象套数组、数组再套对象——接口数据的标准长相,先看清结构再动手。
- 第 12~14 行(准备区):
list起个短名字少打字;total从 0 开始累加;best先假设第 0 个是冠军,后面遇强则换。 - 第 16~21 行(循环区):for...of 逐个学生累加分数;
stu.score > best.score就换冠军——典型的「打擂台」算法。 - 第 23~24 行(播报区):
list.length取人数,模板字符串拼结果。平均分有小数很正常,介意就用.toFixed(1)保留一位。
📝 本章小结
- 取值规律:对象
.属性,数组[下标],从外往内拆 - 数组遍历用
for...of/map/filter;纯对象用Object.keys/Object.entries - 深层取值用
?.可选链,中间缺层返回undefined而不是报错 - 先看结构、再写代码——拿到嵌套数据先打印出来看一眼
动手改
- 给
report.scores再加一个学生,看看平均分和冠军怎么变 - 用
filter挑出 90 分以上的学生 - 故意写
report.teachers[0].name,先看报错,再改成?.写法让它安静返回 undefined