JavaScript数组降维之将二维数组转为一维数组的五种方案
作者: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+ | ⭐⭐⭐⭐ | 🌟🌟🌟🌟 |
| 递归/迭代 | 层级不确定,或需自定义过滤逻辑 | 所有环境 | ⭐⭐ (递归有开销) | 🌟🌟🌟 |
最佳实践建议
- 日常开发:直接使用
arr.flat()。如果需要考虑 IE,引入core-js等 Polyfill 库即可。 - 高性能要求:如果数组非常大(百万级),避免使用
reduce配合展开运算符[...acc, ...item],因为它会频繁创建新数组。推荐使用flat()或传统的for循环 +push。 - 复杂逻辑:如果在扁平化的同时需要过滤数据或转换格式,
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二维数组转为一维数组的资料请关注脚本之家其它相关文章!
