请求解析:利用对象解构结合reduce统计数组对象中重复值出现次数的原理
解惑:对象解构默认值与reduce统计逻辑
嘿,这问题问得特别到位——我当初刚摸对象解构和reduce的时候,也对着类似的代码愣了好一会儿!咱们一步步拆解清楚,你就能彻底搞懂啦。
核心疑惑:为什么空对象解构没报错?
你提到的const {A = 0, B = 0, C = 0} = groups;这行,关键在于对象解构的默认值机制,和你想的不一样:
- 当你解构一个对象的属性时,如果该属性不存在,或者属性值是
undefined,解构时的= 默认值就会生效,给变量赋值默认值,而不是抛出错误。 - 这里
groups的初始值是空对象{},所以groups.A、groups.B、groups.C都是undefined,刚好触发了默认值规则,所以变量A、B、C会被赋值为0,完全不会报错。
举个简单的例子对比:
// 情况1:解构空对象+默认值 → 正常赋值0 const {x = 0} = {}; console.log(x); // 输出0 // 情况2:解构空对象但无默认值 → 变量为undefined,也不会报错 const {y} = {}; console.log(y); // 输出undefined // 情况3:解构undefined才会报错(比如reduce没传初始值时第一次的groups) const {z} = undefined; // 抛出 TypeError: Cannot destructure property 'z' of 'undefined' as it is undefined.
结合reduce的完整执行逻辑
咱们把你那段代码补全,再走一遍流程,你就能明白统计的原理了:
const people = [ {name: 'John', group: 'A'}, {name: 'Andrew', group: 'C'}, {name: 'Peter', group: 'A'}, {name: 'James', group: 'B'}, {name: 'Hanna', group: 'A'}, {name: 'Adam', group: 'B'}, ]; const groupInfo = people.reduce((groups, person) => { const {A = 0, B = 0, C = 0} = groups; // 根据当前用户的group更新计数 switch(person.group) { case 'A': return {A: A + 1, B, C}; // 返回新对象,A计数+1,其他保持不变 case 'B': return {A, B: B + 1, C}; case 'C': return {A, B, C: C + 1}; default: return groups; // 未知group直接返回原对象 } }, {}) // 初始值是空对象{} console.log(groupInfo); // 输出 {A: 3, B: 2, C: 1}
执行流程:
- 第一次迭代:
groups是初始空对象{},解构得到A=0,B=0,C=0;当前person是John(group A),返回{A:1,B:0,C:0},这个对象会作为下一次迭代的groups。 - 第二次迭代:
groups是{A:1,B:0,C:0},解构得到A=1,B=0,C=0;当前person是Andrew(group C),返回{A:1,B:0,C:1}。 - 后续迭代以此类推,每次都基于上一次的统计结果更新对应组的计数,最终得到所有组的人数统计。
额外优化:更灵活的写法
如果你的分组不止A/B/C,上面的switch写法就不够灵活了,推荐用动态属性名的写法,不用提前枚举所有分组:
const groupInfo = people.reduce((groups, person) => { const group = person.group; // 用逻辑或处理不存在的分组,默认取0再加1 return { ...groups, // 复制之前的统计结果 [group]: (groups[group] || 0) + 1 // 动态更新当前组的计数 }; }, {})
这种写法不管有多少个分组都能适配,逻辑也更简洁~
内容的提问来源于stack exchange,提问作者Echo
相关产品推荐
相关产品推荐

