JavaScript篇:数组扁平化:从‘千层饼’到‘一马平川’的六种神操作 🥞→📜

大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

技术qq交流群:906392632

大家好,我是小杨,做了6年前端。今天要聊一个看似简单却让无数新手抓狂的话题------数组扁平化 。还记得我第一次面试时被问到"如何拍平多维数组",当场表演了"用递归递归递归..."的卡带现场,现在想起来脚趾还能抠出三室一厅 😅。今天就把这些年的经验总结成六大必杀技,保你看完直呼:"原来还能这么玩!"


一、生活场景:什么叫"数组不扁平"?

想象你收拾衣柜:

  • 千层饼数组[袜子, [裤子, [上衣, 腰带]], 鞋子](找双袜子要翻三层)
  • 扁平数组[袜子, 裤子,上衣,腰带,鞋子](一目了然)

需求:把嵌套数组变成一维数组,就是扁平化!


二、青铜选手:flat()方法(ES10真香)

javascript 复制代码
const messyCloset = ['袜子', ['裤子', ['上衣', '腰带']], '鞋子'];

// 1. 默认只拍平一层
const level1 = messyCloset.flat(); 
// ['袜子', '裤子', ['上衣', '腰带'], '鞋子']

// 2. 传入Infinity直接全平
const allFlat = messyCloset.flat(Infinity);
// ['袜子', '裤子', '上衣', '腰带', '鞋子']

我的翻车史

曾经以为flat(2)flat(Infinity)效果一样,直到遇到五层嵌套数组...


三、白银选手:reduce+递归(经典永流传)

javascript 复制代码
function flatten(arr) {
  return arr.reduce((result, item) => {
    return result.concat(
      Array.isArray(item) ? flatten(item) : item
    );
  }, []);
}

const myCloset = ['👖', ['👔', ['🧦']], '👟'];
console.log(flatten(myCloset)); // ['👖', '👔', '🧦', '👟']

适用场景

  • 需要兼容老浏览器时
  • 面试官盯着你手写实现时 😏

四、黄金选手:toString妙用(数字数组专属)

javascript 复制代码
const numLayers = [1, [2, [3, [4]]]];

// 1. 转字符串再分割
const strFlat = numLayers.toString().split(','); 
// ['1', '2', '3', '4']

// 2. 转数字(需处理非数字项)
const numFlat = strFlat.map(Number); 
// [1, 2, 3, 4]

致命缺陷

  • 会把[1, 'a']变成['1', 'a']
  • 遇到null, undefined直接转字符串

五、铂金选手:生成器函数(优雅处理海量数据)

javascript 复制代码
function* flattenGen(arr) {
  for (const item of arr) {
    Array.isArray(item) ? yield* flattenGen(item) : yield item;
  }
}

const hugeArray = [1, [2, [3, [4, ...[1000000个项]]]];
const flattened = [...flattenGen(hugeArray)]; // 按需生成不爆内存

性能优势

处理超大规模数组时,不会一次性占用大量内存


六、钻石选手:栈结构迭代(避免递归爆栈)

javascript 复制代码
function flattenStack(arr) {
  const stack = [...arr];
  const result = [];
  
  while (stack.length) {
    const next = stack.pop();
    Array.isArray(next) ? stack.push(...next) : result.push(next);
  }
  
  return result.reverse();
}

const deepArray = [1, [2, [3, [4]]];
console.log(flattenStack(deepArray)); // [1, 2, 3, 4]

适用场景

  • 嵌套层级极深时(递归可能栈溢出)
  • 需要控制遍历顺序时

七、王者选手:Array.prototype.flatMap (ES2019)

javascript 复制代码
// 先map再flat(1)的语法糖
const data = [1, [2], 3];
const processed = data.flatMap(item => 
  Array.isArray(item) ? item : [item * 2]
);
// [2, 2, 6] 

神技巧

flatMap实现过滤+展开二合一:

javascript 复制代码
const mixed = [1, 2, , , 5];
const compact = mixed.flatMap(x => x || []);
// [1, 2, 5] (自动跳过空值)

八、终极选择指南

场景 推荐方案 原因
现代浏览器环境 flat(Infinity) 原生API性能最佳
需要兼容IE reduce+递归 兼容性好
纯数字数组 toString+split 取巧但高效
超大数据量 生成器函数 内存友好
需要控制遍历顺序 栈结构迭代 避免递归爆栈
需要边处理边展开 flatMap 代码最简洁

九、真实案例:树形菜单扁平化

javascript 复制代码
// 原始树形数据
const menuTree = [
  {
    name: '文件',
    children: [
      { name: '新建' },
      { name: '打开', children: [{ name: '从云端' }] }
    ]
  }
];

// 递归提取所有节点名
function getAllNames(items) {
  return items.flatMap(item => [
    item.name,
    ...(item.children ? getAllNames(item.children) : [])
  ]);
}

console.log(getAllNames(menuTree)); 
// ['文件', '新建', '打开', '从云端']

十、总结:一句话记住各方案

  • flat():官方指定快乐锤 🔨
  • reduce:面试必备手写题 ✍️
  • toString:数字数组急救包 🚑
  • 生成器:海量数据救世主 🦸
  • 栈迭代:深度嵌套终结者 💣
  • flatMap:过滤展开二合一 🥇

最后灵魂提问:你们团队用什么方案?有没有更骚的操作?评论区见真章! 👇

相关推荐
用户90738703648646 分钟前
pnpm是如何解决幻影依赖的?
前端
寒山李白11 分钟前
Java 依赖注入、控制反转与面向切面:面试深度解析
java·开发语言·面试·依赖注入·控制反转·面向切面
树上有只程序猿13 分钟前
Claude 4提升码农生产力的5种高级方式
前端
傻球14 分钟前
没想到干前端2年了还能用上高中物理运动学知识
前端·react.js·开源
咚咚咚ddd14 分钟前
前端组件:pc端通用新手引导组件最佳实践(React)
前端·react.js
Lazy_zheng14 分钟前
🚀 前端开发福音:用 json-server 快速搭建本地 Mock 数据服务
前端·javascript·vue.js
HJ_Coder15 分钟前
基于Proxyman的实时解密和预览方案
前端
用户25191624271115 分钟前
ES6之块级绑定
javascript
Gixy15 分钟前
聊聊纯函数与不可变数据结构
前端·设计模式
ZzMemory16 分钟前
藏起来的JS(四) - GC(垃圾回收机制)
前端·javascript·面试