又到年底了。在AI工具的冲击下,普通前端开发者的职场道路似乎更加艰难。

2025年的求职市场早已不是几年前的光景——不再是和面试官简单对答几句就能通过。如今很多面试直接要求手写代码,而且明确规定不能使用AI工具辅助。说实话,我对这种考察方式确实有些抵触。

回归正题,说说今天面试遇到的一道题:数组扁平化。话不多说,直接上代码分析。

方法1:递归forEach版 ✅

const flat = (arr) => {
  let newArr = []
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      newArr = newArr.concat(flat(item))
    } else {
      newArr.push(item)
    }
  })
  return newArr
}

优点

  • 逻辑清晰,易于理解

  • 递归思想体现明确

  • 使用forEach避免手动索引

缺点

  • 频繁使用concat创建新数组,性能较差

  • 每次递归都创建新的newArr数组

方法2:reduce递归版 ✅


const flat2 = (arr) => {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flat2(cur) : cur)
  }, [])
}

优点

  • 代码简洁优雅

  • reduce天然适合累积操作

  • 函数式编程风格

缺点

  • 同样存在concat的性能问题

  • 对于不熟悉reduce的开发者可读性稍差

  • 每次迭代都创建新数组

方法3:迭代拍平版 

const flat3 = (arr) => {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr)
  }
  return arr
}

优点

  • 迭代而非递归,避免栈溢出风险

  • 思路直观:不断展开直到没有嵌套

缺点

  • 每次循环都检查整个数组(some方法)

  • 多次创建中间数组,性能最差

  • 会修改原数组引用(arr = [].concat(...arr)

方法4:原生flat版 🏆

const flat4 = (arr) => {
  return arr.flat(Infinity)
}

优点

  • 浏览器原生实现,性能最佳

  • 语义清晰,维护成本低

缺点

  • 兼容性问题(IE不支持)

  • 无法控制扁平化深度以外的逻辑

  • 面试中不被允许使用(考察手写能力)

方法5:for...of递归版

function flat5(arr) {
  let res = []
  for(let item of arr) {
    if(Array.isArray(item)) {
      res = res.concat(flat5(item))
    } else {
      res.push(item)
    }
  }
  return res
}

优点

  • 使用for...of语法现代简洁

  • 不会改变原始数组,返回新数组

缺点

  • 对于非常大的嵌套数组,递归可能导致栈溢出

  • 只能扁平化数组,其他可迭代对象(如 Set、Map)不会被扁平化

性能对比总结

方法 时间复杂度 空间复杂度 可读性 适用场景
方法1 O(n) O(n) 通用递归实现
方法2 O(n) O(n) 函数式偏好
方法3 O(n×k) O(n) 避免递归栈溢出
方法4 O(n) O(n) 生产环境首选
方法5 O(1) O(1) 不推荐

建议

  1. 面试准备:掌握方法1或2的递归实现

  2. 实际开发:优先使用arr.flat(Infinity)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐