前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Array.prototype.flat 默认深度 flatMap 区别
JavaScript数组与集合

flat 默认展开几层?flatMap 和先 map 再 flat 有什么不同?

flat() 不传参数时深度是 1,只把第一层子数组拆开,更深的保持原样,想全部拍平写 flat(Infinity)。而 flatMap(fn) 的结果和 map(fn).flat(1) 一样,区别是它一次遍历完成、不创建中间数组,而且只能展开一层。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数组与集合
先看核心答案读代码示例
理解线索

两个方法各管什么

  1. flat(depth)按指定深度递归拆开子数组,顺便去掉空位
  2. flatMap(fn)先对每项调用 fn,返回的数组拆一层拼进结果
  3. 回调返回值返回数组会被拆开,返回非数组值原样作为一项

flat 和 flatMap 只拆数组,回调返回 Set 或字符串不会被展开,会整体作为一项放进结果。

核心回答

先记住这个答案

Array.prototype.flat 的默认深度是 1,只把第一层子数组的元素拼进新数组,更深的嵌套保持原样。要展开更多层可以传 2、3,或者传 Infinity 一直拍平到底。flatMap(fn) 的结果等价于 arr.map(fn).flat(1):先对每个元素调用回调,再把返回的数组展开一层。区别在于 flatMap 只遍历一次、不会生成 map 那一步的中间数组,而且深度固定是 1,不能调整。因为回调可以返回空数组或多元素数组,flatMap 能同时完成过滤和一对多映射,结果长度可以和原数组不同。

  • flat() 默认深度 1,flat(Infinity) 拍到底
  • flatMap(fn) 结果等于 map(fn).flat(1)
  • flatMap 深度固定为 1,第二个参数是 thisArg
  • 回调返回 [] 就是删除,返回多项就是展开

flat 的深度参数

用一个四层嵌套的数组看不同深度的效果。

默认一层、指定层数和拍到底JavaScript
const nested = [1, [2, [3, [4]]]]
console.log(JSON.stringify(nested.flat())) // 默认深度 1
console.log(JSON.stringify(nested.flat(2)))
console.log(JSON.stringify(nested.flat(Infinity))) // 全部拍平

console.log(JSON.stringify([1, , 3].flat())) // 空位被去掉
查看输出与解释
[1,2,[3,[4]]]
[1,2,3,[4]]
[1,2,3,4]
[1,3]

深度可以理解成「拆几层包装」。flat() 拆一层,[2, [3, [4]]] 被拆开,里面的 [3, [4]] 原样保留。拍到底用 Infinity,但数据层级来自用户输入或者接口时要当心,特别深的嵌套会让递归开销变大。 最后一行是个容易忽略的副作用:flat 会去掉空位,结果里只剩实际存在的元素。所以 arr.flat(0) 有时被用来「压缩」稀疏数组,不过写 arr.filter(() => true) 意图更清楚。

flatMap 和 map 加 flat

flatMap 最常见的用途是「一项变多项」和「映射时顺便过滤」。

拆分、过滤和只拆一层JavaScript
const words = ['hello world', 'hi']
console.log(JSON.stringify(words.map((s) => s.split(' ')))) // 嵌套了
console.log(JSON.stringify(words.flatMap((s) => s.split(' ')))) // 拆开一层

// 返回 [] 相当于删除,返回两项相当于展开
console.log(JSON.stringify([1, 2, 3].flatMap((x) => (x === 2 ? [] : [x, x * 10]))))

console.log(JSON.stringify([[1], [2]].flatMap((x) => [x]))) // 只拆一层
查看输出与解释
[["hello","world"],["hi"]]
["hello","world","hi"]
[1,10,3,30]
[[1],[2]]

把一句话拆成单词、把订单拆成商品行这类场景,map 会得到二维数组,flatMap 直接得到平铺的结果。第三行里,回调对 2 返回空数组,展开后什么都没有,2 就被删掉了;对其它值返回两项,结果就多出一项。 最后一行说明深度固定为 1。回调返回 [[1]],只拆掉最外层,剩下 [1]。需要更深的展开,只能写回 map(fn).flat(depth)。

为什么不直接用 map 加 flat
结果一样,但 map 会先生成一个完整的中间数组,flat 再遍历它生成最终数组。flatMap 在一次遍历里直接写出最终结果,少一个中间数组。数据量不大时差别感知不到,主要好处还是读起来更直接。
回答前,多想一步

容易答错的地方

以为 flat() 默认会全部拍平
默认只拆一层。[1, [2, [3]]].flat() 得到 [1, 2, [3]],不是 [1, 2, 3]。从 lodash 的 flattenDeep 迁移过来时最容易写错。
给 flatMap 传深度
flatMap 的第二个参数是 thisArg,用来指定回调里的 this。所以 arr.flatMap(fn, 2) 不会展开两层,那个 2 只是被当成了 this,深度仍然是 1。
以为回调返回的任何可迭代对象都会被展开
只有数组会被展开。回调返回 new Set([1, 2]) 或者字符串 'ab',都会原样作为一项放进结果。要展开 Set,在回调里先写 [...set]。
试着用自己的话回答

面试官还会怎么问?

不用 flat,手写一个指定深度的拍平?

用 reduce 递归:遍历每一项,如果是数组并且 depth > 0,就对它递归调用并传 depth - 1,把结果拼进累加器;否则直接 push。深度很大时可以改成用栈迭代,避免递归层数太深。

flat 会改变原数组吗?

不会。flat 和 flatMap 都返回新数组,原数组不变。但新数组是浅拷贝,里面没被拆开的子数组和对象仍然是原来的引用。

flatMap 和 filter 加 map 该怎么选?

先过滤后映射,而且每项只对应零或一个结果时,filter(...).map(...) 的意图最清楚。需要一项对应多项,或者过滤条件依赖映射时才算出来的值,flatMap 更合适,因为它能在一个回调里同时决定「要不要」和「变成什么」。

从一道题,走向一组知识

把知识连起来

数组与集合

splice 和 slice 有什么区别,哪个会改原数组?

flat 和 slice 返回新数组,splice 会改原数组,放在一起能理清哪些数组方法有副作用。

数组与集合

Map 和普通对象的键有什么本质区别,什么时候该用 Map?

嵌套数据拍平成列表后,常要按 id 建索引,这时就要选 Map 还是普通对象。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Array.prototype.flat()
  • Array.prototype.flatMap()

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. flat 的深度参数
  3. flatMap 和 map 加 flat
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑