标准答案

  1. forEach:适合遍历并执行副作用,例如打印、埋点、调用外部函数。它不返回新数组,也不能用 break 正常中断。
  2. map、filter、reduce:map 适合把每一项转换成另一项,返回等长新数组;filter 用来筛选满足条件的元素,返回新数组;reduce 用来把数组聚合成一个值,例如求和、分组、构造索引对象。
  3. find、some、every:find 返回第一个满足条件的元素,找不到返回 undefined;some 判断是否至少有一个满足条件;every 判断是否所有元素都满足条件。它们都适合表达“查找或判断”,不需要手动维护标记变量。
  4. 工程取舍:需要转换结果用 map,需要筛选用 filter,需要聚合用 reduce,需要提前判断真假用 some/every,需要提前中断且逻辑复杂时用 for...of 更直观。不要为了“高级”强行用 reduce 写难读的代码。

题目解析

数组方法的价值不只是少写循环,而是让代码意图更明确。map、filter、some、every 这些方法本身没有难度,关键是不要把所有逻辑都写成 forEach 或 reduce。

forEach 的定位是副作用遍历,它不返回结果,也不适合中断;map/filter 的返回值有明确语义;some/every/find 有短路能力。这些差异会直接影响代码可读性和维护成本。

reduce 是最容易被滥用的方法。它适合聚合、分组、构建索引,但如果只是筛选或映射,用 reduce 反而会让代码难读。选方法是为了表达业务意图,不是为了显得高级。

如果场景需要 break、continue、await 串行处理,传统 for 或 for...of 反而更清楚。数组方法不是替代所有循环的银弹。

代码示例

同一批数据可以按目标选择不同数组方法,关键是让代码语义和业务意图一致。

JavaScript
const users = [
  { id: 1, role: 'admin', active: true },
  { id: 2, role: 'user', active: false }
]

const ids = users.map(user => user.id)
const activeUsers = users.filter(user => user.active)
const hasAdmin = users.some(user => user.role === 'admin')
const userById = users.reduce((map, user) => {
  map[user.id] = user
  return map
}, {})

常见误区

  • 用 map 做副作用但不使用返回值。
  • 用 reduce 写过度复杂的逻辑,降低可读性。
  • 误以为 forEach 可以用 return 终止整个循环。

作者信息