
在日常开发中,我们经常会遇到嵌套数组(nested arrays)的处理需求。例如,从 API 接口返回的数据可能包含多层结构,而我们需要将其“拍平”成一维数组以便后续操作。本文将以如下示例数据为切入点,系统性地介绍四种主流的数组扁平化方法,并从语法简洁性、执行性能、兼容性、适用场景等多个维度进行对比分析。
const arr = [[1, 2], [3, 4], [5, 6]];
// 目标:[1, 2, 3, 4, 5, 6]Array.prototype.flat()(现代标准,推荐)ES2019(ECMAScript 2019)引入了 flat() 方法,专门用于数组扁平化,语法简洁直观:
const merged = arr.flat();
console.log(merged); // [1, 2, 3, 4, 5, 6]默认只展开一层嵌套。
可通过传入参数指定展开深度:
const deepArr = [[[1, 2]], [[3, 4]]];
console.log(deepArr.flat(2)); // [[1, 2], [3, 4]]
console.log(deepArr.flat(Infinity)); // [1, 2, 3, 4] — 完全扁平化flat() 是首选方案。concat()利用 ES6 的扩展运算符(spread operator)将子数组作为参数传入 concat:
const merged = [].concat(...arr);
console.log(merged); // [1, 2, 3, 4, 5, 6]...arr 将 [[1,2], [3,4], [5,6]] 展开为三个独立参数:[1,2], [3,4], [5,6]。[].concat(a, b, c) 等价于合并这些数组。✅ 优点:
❌ 缺点:
concat 接收的是展开后的参数列表)。📌 适用建议:适合中小型数组、追求代码简洁性的场景。
Array.prototype.reduce()const merged = arr.reduce((acc, subArr) => acc.concat(subArr), []);const merged = arr.reduce((acc, subArr) => [...acc, ...subArr], []);concat 都会创建一个新数组,时间复杂度为 O(n²),大数据量下性能较差。concat,但 [...acc, ...subArr] 同样会复制整个累加器数组,内存开销大。需要兼容 ES5 或更老环境(如 IE11)。
需要在扁平化过程中加入自定义逻辑(如过滤、映射等):
arr.reduce((acc, sub) => {
return acc.concat(sub.filter(x => x > 2));
}, []);for...of 循环 + push(...subArr)const merged = [];
for (const subArr of arr) {
merged.push(...subArr);
}
console.log(merged); // [1, 2, 3, 4, 5, 6]reduce 或 concat,循环开销极小。仍受限于扩展运算符的参数数量上限(理论上 V8 引擎限制约为 65535 个参数),若单个子数组极大(如长度 > 10⁵),可改用 push.apply 或分批处理:
for (const subArr of arr) {
Array.prototype.push.apply(merged, subArr);
}但
push.apply在极端情况下也可能栈溢出,最稳妥的方式是使用普通for循环逐个push。
方法 | 语法简洁性 | 执行性能 | 内存效率 | 兼容性 | 适用嵌套深度 | 是否修改原数组 |
|---|---|---|---|---|---|---|
arr.flat() | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ES2019+ | 可控(默认1层) | 否 |
[].concat(...arr) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ES6+ | 仅1层 | 否 |
reduce() + concat | ⭐⭐⭐ | ⭐ | ⭐ | 广泛(ES5+) | 仅1层 | 否 |
for...of + push(...) | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ES6+ | 仅1层 | 否 |
注:⭐ 越多表示越优。
arr.flat() —— 简洁、安全、高效。
reduce 或手动 for 循环,并搭配 Babel 转译。
for...of + push,并注意单个子数组长度限制。
reduce,灵活组合业务逻辑。
若面对如下结构:
const deeplyNested = [1, [2, [3, [4, [5]]]]];可封装递归函数或使用 flat(Infinity):
const flatten = arr => arr.flat(Infinity);
// 或
const flatten = arr => arr.reduce(
(acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val),
[]
);💡 提示:
flat(Infinity)在大多数现代引擎中已高度优化,通常优于手写递归。
数组扁平化虽是一个“小问题”,却能反映出开发者对语言特性、性能边界和工程实践的理解深度。在实际项目中,应根据运行环境、数据规模、维护成本综合选择方案。对于绝大多数现代前端或 Node.js 应用,arr.flat() 已足够优雅且高效——简单,才是终极的复杂。