js 数组 map forEach filter 区别
map 转换并返回等长新数组,filter 筛选并返回长度可变的新数组,forEach 仅遍历执行副作用且返回 undefined、不能链式调用;三者均全量遍历且不改变原数组本身,应按语义选用,需 break 或 await 时改用 for
**结论:map 用来“转换”,返回一个长度与原数组相同的新数组;filter 用来“筛选”,返回长度可变的新数组;forEach 只用来“遍历执行副作用”,固定返回 undefined,无法链式调用。** 三者都接收 (element, index, array) 三个回调参数,都属于 ES5(2009 年)引入的数组迭代方法,底层都是 O(n) 全量遍历,选择依据应该是语义而不是性能。
map 和 forEach 有什么区别
结论:map 的返回值是新数组,forEach 的返回值永远是 undefined——这是两者唯一不可互换的差别。
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2); // [2, 4, 6]
const nothing = nums.forEach(n => n * 2); // undefined
因为 forEach 返回 undefined,所以 arr.forEach(...).filter(...) 会直接抛 TypeError: Cannot read properties of undefined。只要你的下一步还想继续链式处理数据,就必须用 map。
另一个高频问题(坑)是:map 的回调必须写 return,用箭头函数加花括号而漏掉 return 时,会得到一个全是 undefined 的等长数组。forEach 则不需要返回值,它的目的就是副作用——发请求、console.log、往外部变量 push。
filter 和 map 有什么区别
结论:map 输出长度恒等于输入长度,filter 输出长度只能小于或等于输入长度。
filter 的回调需要返回一个布尔值(truthy / falsy),返回真值的元素进入结果数组。它不能修改元素值,只能决定元素去留:
const users = [{age: 17}, {age: 20}, {age: 30}];
users.filter(u => u.age >= 18); // [{age:20}, {age:30}],长度 3 → 2
常见错误是在 filter 回调里写赋值而不是比较,例如 filter(u => u.age = 18),赋值表达式返回 18(truthy),结果会原样返回全部元素,并且顺手改坏了原数据。想“筛选 + 变形”就链式写 filter 再 map,顺序建议先 filter 后 map,能少跑一半回调。
三个方法会改变原数组吗
结论:三个方法本身都不改变原数组的长度和引用,但回调内部可以改到原数组里的对象。
map、filter、forEach 都只做遍历,不会 push/splice 原数组。但如果元素是引用类型,回调参数拿到的是同一个对象引用,写 arr.forEach(o => o.done = true) 会真实修改原对象。另外,遍历过程中新增的元素不会被访问到,删除的元素会被跳过;三个方法都会跳过稀疏数组的空位([1, , 3] 只回调 2 次)。
该用哪个:一张决策表
结论:要新数组且一一对应用 map,要新数组且数量会变用 filter,不要返回值用 forEach,要中途 break 或 await 就换 for...of。
- 需要
break/continue/return提前退出:forEach做不到,只能抛异常或改用for/for...of。 - 回调里要
await:forEach不会等待,arr.forEach(async ...)会在第一个 await 前就结束;应改用for...of或await Promise.all(arr.map(async ...))。 - 只需要布尔结论:用
some/every,它们遇到确定结果就短路,比filter快。 map(parseInt)是经典错误:['1','2','3'].map(parseInt)得到[1, NaN, NaN],因为map会把索引当作第二个参数传进去,变成parseInt('2', 1)这种非法进制。正确写法是map(s => parseInt(s, 10))。
三者都是全量遍历,V8 下的耗时差异在微秒级以下,不要为了“性能”在 map 和 forEach 之间纠结——按语义选,代码可读性收益远大于那点差异。
总结一句:**要结果数组,看数量是否一一对应来决定 map 还是 filter;不要结果数组,用 forEach;需要控制流,直接用 for...of。**
转载请注明出处,版权归原作者所有。