请详细讲解使用reduce统计数组元素出现次数的代码及回调函数逻辑
详解JavaScript中reduce统计数组元素出现次数的回调函数逻辑
先把完整代码和运行结果贴出来,方便对照:
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; var countedNames = names.reduce(function (allNames, name) { if (name in allNames) { allNames[name]++; } else { allNames[name] = 1; } return allNames; }, {});
运行后结果:
countedNames is: // { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
核心逻辑拆解:reduce的回调函数到底在做什么?
reduce方法的本质是遍历数组,用一个"累加器"逐步收集处理结果。这里的回调函数有两个关键参数:
allNames: 这就是我们的累加器,每次迭代都会把处理后的结果存到它里面,然后返回给下一次迭代使用。一开始它是我们传入的初始值{}(空对象)。name: 当前正在遍历的数组元素,也就是我们要统计的名字。
接下来我们一步步走一遍每一次迭代的过程,就能完全明白它的工作原理:
1. 第一次迭代:处理第一个元素 'Alice'
- 此时
allNames是初始的空对象{} - 检查
'Alice' in allNames?空对象里没有这个属性,结果是false - 执行
allNames['Alice'] = 1,现在allNames变成{ 'Alice': 1 } - 把这个对象返回,作为下一次迭代的
allNames
2. 第二次迭代:处理第二个元素 'Bob'
- 当前
allNames是{ 'Alice': 1 } - 检查
'Bob' in allNames?里面没有Bob,结果false - 执行
allNames['Bob'] = 1,allNames更新为{ 'Alice': 1, 'Bob': 1 } - 返回这个对象给下一次迭代
3. 第三次迭代:处理第三个元素 'Tiff'
- 当前
allNames是{ 'Alice': 1, 'Bob': 1 } - 检查
'Tiff'是否存在?不存在,所以设置allNames['Tiff'] = 1 allNames变成{ 'Alice': 1, 'Bob': 1, 'Tiff': 1 },返回它
4. 第四次迭代:处理第四个元素 'Bruce'
- 当前
allNames是{ 'Alice': 1, 'Bob': 1, 'Tiff': 1 } - 检查
'Bruce'不存在,设置allNames['Bruce'] = 1 allNames更新为{ 'Alice': 1, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 },返回它
5. 第五次迭代:处理第五个元素 'Alice'
- 当前
allNames是{ 'Alice': 1, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } - 检查
'Alice' in allNames?这次存在了,结果true - 执行
allNames['Alice']++,把原来的1加1变成2,allNames变成{ 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } - 返回这个最终的对象
当数组的所有元素都遍历完成后,reduce会把最后一次返回的allNames赋值给countedNames,这就是我们看到的统计结果啦。
顺便提一句,这个回调函数还可以简化成更简洁的写法,比如用逻辑短路来替代if-else:
var countedNames = names.reduce(function(allNames, name) { allNames[name] = (allNames[name] || 0) + 1; return allNames; }, {});
原理是一样的,只是写法更紧凑而已。
内容的提问来源于stack exchange,提问作者Enthu
相关产品推荐
相关产品推荐

