flatMap() 是 JavaScript 中融合 map() 和 flat(1) 的数组方法,先映射后一层扁平化,支持隐式过滤(返回[]跳过)、一对多展开及单次遍历优化,但不支持深层扁平或异步操作。

flatMap() 是 JavaScript 中一个非常实用的数组方法,它把 map() 和 flat(1) 合并为一步:先对每个元素执行映射函数(该函数必须返回一个数组),再将所有结果数组“一层扁平化”拼接成新数组。正因如此,它天然适合在单次遍历中完成“过滤 → 展开 → 映射”的复合逻辑——关键在于让映射函数根据条件决定返回一个含值的数组(保留并展开)或空数组(等效于过滤掉)。
用空数组实现隐式过滤
flatMap 不会跳过 undefined 或 null,但会跳过空数组。因此最简洁的过滤方式是:条件不满足时返回 [],满足时返回映射后的数组(哪怕只有一个元素)。
- 例如,提取字符串数组中每个单词的首字母,但只处理长度 ≥ 3 的字符串:
const initials = words.flatMap(word =>
word.length >= 3 ? [word[0]] : []
);
// → ['h', 'w']
自然支持多值展开(一对多映射)
当一个输入需要生成多个输出项时,flatMap 比 map + flat 更直接。比如把嵌套结构“拍平并转换”:
- 将用户列表中每个用户的标签(tags 数组)提取出来,并转为小写、去重后的扁平列表:
{ name: 'Alice', tags: ['JS', 'React'] },
{ name: 'Bob', tags: ['CSS', 'JS'] }
];
const allTags = [...new Set(
users.flatMap(u => u.tags.map(t => t.toLowerCase()))
)];
// → ['js', 'react', 'css']
替代 filter + map + flat 的冗余链式调用
传统写法需三次遍历:arr.filter(...).map(...).flat();而 flatMap 一次遍历即可,性能更优,语义也更紧凑。
- 对比示例:筛选出偶数,再拆成各位数字:
[12, 34, 5, 67, 80].filter(n => n % 2 === 0)
.map(n => String(n).split('').map(Number))
.flat();
// → [1, 2, 3, 4, 8, 0]
// flatMap 方式(1 次遍历)
[12, 34, 5, 67, 80].flatMap(n =>
n % 2 === 0
? String(n).split('').map(Number)
: []
);
// → [1, 2, 3, 4, 8, 0]
注意边界:不能替代深层扁平化或异步操作
flatMap 只做一层扁平(等价于 flat(1)),如果映射结果本身是多层嵌套数组,需额外 flat;它也不支持 async 函数——返回 Promise 数组不会被 await,此时应改用 for...of 或 Promise.all。
- 若需深度展平,可组合使用:
arr.flatMap(fn).flat(Infinity) - 若映射逻辑含异步,不要写
flatMap(async () => ...),那只会得到 Promise[],应改用await Promise.all(arr.map(async () => ...)).flat()

















