foreach用于执行副作用且不返回值,map用于生成新数组且必须显式返回,filter用于筛选且回调必须返回明确布尔值。

forEach、map、filter 不是“换种写法的 for 循环”,它们职责不同,混用或误赋值会直接导致 undefined、空数组、内存浪费甚至逻辑崩溃。
forEach 用来执行副作用,别指望它返回数据
它只做事情,不产出结果。常见错误是把它当 map 用,然后发现变量是 undefined:
-
const result = arr.forEach(x => x * 2)→result一定是undefined - 想中断循环?
return或break在回调里完全无效;真要提前退出,改用for或some/every - 修改原数组时要注意:对引用类型(如对象)可直接改属性,但对值类型(如数字、字符串)赋值无效 ——
arr.forEach(x => x = x * 2)不会改变arr - 异步操作慎用:
await写在forEach回调里不会顺序等待,所有请求会并发发出
map 必须返回值,否则新数组全是 undefined
map 的核心契约是“输入一项,必须输出一项”。漏掉 return 是高频翻车点:
-
arr.map(x => { console.log(x); })→ 返回[undefined, undefined, ...],因为代码块没显式返回 - 正确写法是
arr.map(x => x * 2)或arr.map(x => { return x * 2; }) - 它适合纯转换:取字段(
users.map(u => u.name))、格式化(dates.map(d => d.toISOString()))、预计算(items.map(i => ({...i, total: i.price * i.qty}))) - 返回的新数组可链式接
filter或另一个map,但注意每次调用都新建数组,大数据量时别无谓嵌套多层
filter 靠布尔值筛选,falsy 值会直接丢弃
它的回调函数必须返回明确的 true 或 false,任何隐式转换都危险:
-
arr.filter(x => { x > 3 })→ 没return,实际返回false,整个数组被清空 -
arr.filter(x => x && x.id)→ 如果某项是{id: 0},0是 falsy,会被误删 - 安全写法是显式比较:
arr.filter(x => x.id !== undefined)或arr.filter(Boolean)(仅当确认数据结构干净) - 和
map组合很自然:比如先map提取字段,再filter去空 ——users.map(u => u.email).filter(Boolean)
真正难的不是语法,而是每次写之前问自己一句:这次操作要不要产生新数据?要不要保留原数组?要不要提前终止?答错一个,后面就全是补丁。










