JavaScript数组降维之将二维数组转为一维数组的五种方案

 更新时间:2026年05月08日 09:30:05   作者:yqcoder  
本文介绍了五种数组降维方法,从最简单的Array.prototype.flat()方法,到兼容旧版本的concat;spread方法,再到通用的reduce方法,以及处理任意深度嵌套的递归方法, 兌时建议总结不同方法的特点、适用场景和性能差异,需要的朋友可以参考下

在处理数据时,我们经常会遇到这样的结构:

const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];

我们希望把它变成:

[1, 2, 3, 4, 5, 6];

这个过程被称为 “数组扁平化” (Array Flattening)

很多开发者知道 flat(),但你知道它有哪些替代方案吗?在兼容性要求高的老项目中该怎么办?如果数组层级不确定又该如何处理?

本文将带你掌握 5 种 主流方法,从最简单到最底层,彻底搞定数组降维。

1. 首选方案:Array.prototype.flat()

这是 ES2019 (ES10) 引入的最简单、最直观的方法。

基本用法

flat() 方法会创建一个新数组,其中所有子数组元素以递归方式连接到指定深度。

const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];

// 默认只扁平化一层
const result = arr.flat();
console.log(result); // [1, 2, 3, 4, 5, 6]

控制深度

如果数组嵌套更深,可以传入参数指定深度。

const deepArr = [1, [2, [3, [4]]]];

console.log(deepArr.flat()); // [1, 2, [3, [4]]]       (默认深度 1)
console.log(deepArr.flat(2)); // [1, 2, 3, [4]]         (深度 2)
console.log(deepArr.flat(Infinity)); // [1, 2, 3, 4]      (无限深度,完全扁平)

优点

  • 语法极简,语义清晰。
  • 支持自定义深度。
  • 自动跳过空位(sparse arrays)。

注意

  • 兼容性:IE 不支持。如果需要支持 IE,请使用 Babel 转译或下面的其他方法。

2. 经典方案:concat + spread

flat() 出现之前,这是最常用的“一行代码”解法,适用于仅有一层嵌套的二维数组。

代码实现

利用 Array.prototype.concat() 可以接受多个参数或数组作为参数的特性,结合展开运算符 ...

const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];

// 方法 A: 使用 apply (旧式写法)
const resultA = [].concat.apply([], arr);

// 方法 B: 使用 Spread 运算符 (推荐,更现代)
const resultB = [].concat(...arr);

console.log(resultB); // [1, 2, 3, 4, 5, 6]

局限性

  • 只能处理一层嵌套。如果数组是 [[1, [2]], [3]],结果会是 [1, [2], 3],内部的 [2] 不会被展开。
  • 参数长度限制:如果数组非常大(例如超过几万个元素),...arr 可能会导致调用栈溢出(Maximum call stack size exceeded),因为 concat 的参数个数有限制。

3. 通用方案:reduce 累加器

reduce 是数组处理的神器,它可以灵活地构建任何结构。对于二维数组,我们可以用 reduce 配合 concat 来实现。

代码实现

const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];

const result = arr.reduce((acc, cur) => {
  return acc.concat(cur);
}, []);

console.log(result); // [1, 2, 3, 4, 5, 6]

进阶:配合 Spread

const result = arr.reduce((acc, cur) => [...acc, ...cur], []);

注意[...acc, ...cur] 每次都会创建新数组,性能比 acc.concat(cur) 差,建议优先使用 concat

与 flat() 对比

  • reduce 方案同样默认只处理一层
  • 优点是兼容性极好(ES5 即可支持)。
  • 缺点是代码稍长,不如 flat() 直观。

4. 递归方案:处理任意深度嵌套

如果数据层级不确定(可能是三维、四维甚至更深),或者你需要兼容旧环境且不能使用 flat(Infinity),则需要使用递归

代码实现

function flattenDeep(arr) {
  let result = [];

  arr.forEach((item) => {
    if (Array.isArray(item)) {
      // 如果是数组,递归调用
      result = result.concat(flattenDeep(item));
    } else {
      // 如果不是数组,直接加入
      result.push(item);
    }
  });

  return result;
}

// 测试
const deepArr = [1, [2, [3, [4, 5]]], 6];
console.log(flattenDeep(deepArr)); // [1, 2, 3, 4, 5, 6]

优化版:使用 reduce + 递归

function flattenDeep(arr) {
  return arr.reduce((acc, val) => {
    return acc.concat(Array.isArray(val) ? flattenDeep(val) : val);
  }, []);
}

优点

  • 兼容所有环境。
  • 逻辑清晰,易于理解。

注意

  • 递归过深可能导致栈溢出。对于极深层级的数据,建议使用**栈(Stack)**实现的迭代方式。

5. 选型指南与性能对比

方法适用场景兼容性性能推荐指数
flat()现代项目首选,代码简洁ES2019+ (需 Polyfill for IE)⭐⭐⭐⭐🌟🌟🌟🌟🌟
concat(...arr)确定只有一层嵌套,且数据量不大ES6+⭐⭐⭐🌟🌟🌟
reduce + concat需要兼容旧浏览器,且只有一层嵌套ES5+⭐⭐⭐⭐🌟🌟🌟🌟
递归/迭代层级不确定,或需自定义过滤逻辑所有环境⭐⭐ (递归有开销)🌟🌟🌟

最佳实践建议

  1. 日常开发:直接使用 arr.flat()。如果需要考虑 IE,引入 core-js 等 Polyfill 库即可。
  2. 高性能要求:如果数组非常大(百万级),避免使用 reduce 配合展开运算符 [...acc, ...item],因为它会频繁创建新数组。推荐使用 flat() 或传统的 for 循环 + push
  3. 复杂逻辑:如果在扁平化的同时需要过滤数据或转换格式,reduce 是最灵活的选择。
// 示例:扁平化并只保留偶数
const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];
const evenNumbers = arr.flat().filter((n) => n % 2 === 0);
// [2, 4, 6]

总结

  • 最简单arr.flat()
  • 最兼容(单层)[].concat(...arr)
  • 最灵活(多层/自定义):递归函数或 reduce

掌握这些方法,你就能从容应对任何数组嵌套场景。记住,工具没有好坏,只有适不适合。在现代 Vue/React 项目中,请放心拥抱 flat()

以上就是JavaScript数组降维之将二维数组转为一维数组的五种方案的详细内容,更多关于JavaScript二维数组转为一维数组的资料请关注脚本之家其它相关文章!

相关文章

  • 不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象

    不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象

    JavaScript中的对象模型(object model)并不广为人知,我们再设想:假设JavaScript没有构造函数或者没有new关键字会怎样?事情又会变成什么样的呢?让我们推到以前的重来,感兴趣的朋友可以详细了解下
    2013-01-01
  • js 自带的sort() 方法全面了解

    js 自带的sort() 方法全面了解

    下面小编就为大家带来一篇js 自带的sort() 方法全面了解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • JS中用try catch对代码运行的性能影响分析

    JS中用try catch对代码运行的性能影响分析

    要捕获JavaScript代码中的异常一般会采用 try catch,不过try catch的使用是否是对代码性能产生影响呢?答案是肯定有的,但是有多少不得而知。下面这篇文章就给大家详细介绍了在JS中用try catch对代码运行的性能影响,有需要的朋友们可以参考借鉴。
    2016-12-12
  • 分享8个JavaScript库可更好地处理本地存储

    分享8个JavaScript库可更好地处理本地存储

    这篇文章主要介绍了分享8个JavaScript库可更好地处理本地存储,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 原生js实现日期联动

    原生js实现日期联动

    日期联动算是一个比较常见的功能了,随便度娘一下,你就能找到N多代码,今天给大家介绍的是个人比较常用,代码很简洁,高效,这里推挤给大家。
    2015-01-01
  • BootStrap表单宽度设置方法

    BootStrap表单宽度设置方法

    这篇文章主要介绍了BootStrap表单宽度设置方法,仅仅是小编日常遇到问题记录,写的不好还请见谅,需要的朋友可以参考下
    2017-03-03
  • 使用JavaScript监视有没有被刷新后跳转其他页面

    使用JavaScript监视有没有被刷新后跳转其他页面

    这篇文章主要为大家详细介绍了如何使用JavaScript监视有没有被刷新后跳转其他页面,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下
    2025-01-01
  • JavaScript快速调试的两个技巧

    JavaScript快速调试的两个技巧

    这篇文章主要给大家介绍了关于JavaScript快速调试的两个技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 微信公众平台开发教程(六)获取个性二维码的实例

    微信公众平台开发教程(六)获取个性二维码的实例

    二维码的用处有很多,本篇文章主要介绍了微信公众平台开发教程(六)获取个性二维码的实例,有兴趣的可以了解一下。
    2016-12-12
  • Lab.js初次使用笔记

    Lab.js初次使用笔记

    这篇文章主要介绍了Lab.js初次使用笔记,本文对比了普通动态加载JS文件的技术和使用Lab.js加载JS文件的技术,并给出了Lab.js加载示例,需要的朋友可以参考下
    2015-02-02

最新评论