
本文详解如何遍历包含多个字符串数组的对象,准确统计目标字符串在所有数组中出现的总次数,并提供传统 for 循环与现代函数式编程(reduce + filter)两种高效实现方案。
在实际开发中,我们常遇到结构类似 { key: string[], ... } 的嵌套对象,需跨所有数组统计某字符串(如 'Benicassim')的全局出现频次。初学者易误将数组整体与字符串直接比较(如 festivals[festival] === target),导致逻辑失效——因为 festivals[festival] 是一个数组,而 target 是字符串,二者恒不相等。
正确做法是:先遍历对象的每个属性(即每个数组),再遍历该数组的每个元素,逐一对比并计数。以下是两种推荐实现方式:
✅ 方案一:嵌套 for 循环(清晰直观,兼容性好)
const festivals = {
'Danny': ['Glastonbury','Glastonbury','Leeds','Leeds','Leeds','Benicassim','MadCool'],
'Jimbo': ['Glastonbury','Glastonbury','Leeds','Leeds','Leeds','Leeds','Benicassim','MadCool'],
'Richard': ['Glastonbury','Leeds','Leeds','Benicassim','MadCool'],
'John': ['Glastonbury','Leeds']
};
let totalFestivals = 0;
const target = 'Benicassim';
for (const person in festivals) {
const festivalList = festivals[person];
for (const fest of festivalList) {
if (fest === target) {
totalFestivals++;
}
}
}
console.log(totalFestivals); // 输出: 3⚠️ 注意:使用 for...in 遍历对象时,应确保对象为纯数据对象(无原型污染)。若需更高健壮性,可加 hasOwnProperty 检查;但本例中可省略。
✅ 方案二:函数式链式调用(简洁、声明式、易于复用)
const target = 'Benicassim';
const totalFestivals = Object.entries(festivals).reduce(
(sum, [, festivalsArray]) =>
sum + festivalsArray.filter(fest => fest === target).length,
0
);
console.log(totalFestivals); // 输出: 3该写法利用:
- Object.entries() 将对象转为 [key, value] 元组数组;
- reduce() 累计总数,初始值为 0;
- 解构赋值 [, festivalsArray] 忽略键名(person),专注数组值;
- filter().length 直接获取当前数组中匹配项数量。
? 对比与选型建议
| 维度 | 嵌套 for 循环 | reduce + filter |
|---|---|---|
| 可读性 | 逻辑显式,适合初学者理解 | 更抽象,但语义清晰(“对每组数组求匹配数之和”) |
| 性能 | 略优(单次遍历,无中间数组) | 创建临时过滤数组,内存稍高 |
| 扩展性 | 修改逻辑需手动调整循环体 | 易组合其他方法(如 map 预处理、includes 模糊匹配) |
| 兼容性 | 支持所有 ES5+ 环境 | 需 ES2015+(Object.entries, reduce, filter) |
? 进阶提示
- 若需不区分大小写匹配,可改为 fest.toLowerCase() === target.toLowerCase();
- 若需子串包含(如匹配 'Leed' 在 'Leeds' 中),改用 fest.includes(target);
- 若对象深层嵌套(含多级数组或对象),建议使用递归函数或 Lodash 的 flatMapDeep + countBy。
掌握这两种模式,即可灵活应对各类嵌套数据的聚合统计需求。










