JavaScript中的数组扁平化(Array Flattening)与性能优化
字数 759 2025-11-28 15:34:37
JavaScript中的数组扁平化(Array Flattening)与性能优化
描述
数组扁平化指将多维数组转换为一维数组的过程。例如,将[1, [2, [3, 4]], 5]扁平化为[1, 2, 3, 4, 5]。此操作在数据处理和函数式编程中常见,但实现时需注意嵌套深度、性能及边界情况(如空位处理)。
步骤1:基础递归实现
最直接的方法是递归遍历数组,若元素是子数组则递归展开,否则收集到结果中:
function flattenDeep(arr) {
const result = [];
for (const item of arr) {
if (Array.isArray(item)) {
result.push(...flattenDeep(item)); // 递归展开子数组
} else {
result.push(item);
}
}
return result;
}
// 示例:flattenDeep([1, [2, [3]]]) 返回 [1, 2, 3]
注意:此方法可处理任意嵌套深度,但递归可能导致栈溢出(如嵌套过深),且扩展运算符(...)可能影响大数组性能。
步骤2:使用reduce简化递归
通过reduce替代显式循环,代码更函数式:
function flattenDeep(arr) {
return arr.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val),
[]);
}
优缺点:代码简洁,但concat会创建新数组,频繁调用可能增加内存开销。
步骤3:指定扁平化深度
实际场景可能只需扁平化到特定深度(如深度2)。ES2019的Array.prototype.flat支持深度参数:
// 原生方法(深度为Infinity时完全扁平化)
[1, [2, [3]]].flat(1); // [1, 2, [3]]
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]
// 手动实现指定深度
function flattenDepth(arr, depth = 1) {
return depth > 0
? arr.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flattenDepth(val, depth - 1) : val),
[])
: arr.slice(); // 深度为0时返回副本
}
步骤4:迭代方案避免递归栈溢出
对于极深嵌套数组,可用迭代代替递归。通过栈模拟递归过程:
function flattenIterative(arr) {
const stack = [...arr]; // 初始化栈
const result = [];
while (stack.length) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next); // 将子数组元素压入栈
} else {
result.push(next);
}
}
return result.reverse(); // 因栈的LIFO特性需反转结果
}
优势:避免递归深度限制,但顺序可能受影响(需反转结果)。
步骤5:性能优化与边界处理
- 空位处理:
flat会跳过空位(如[1, , 3]扁平化为[1, 3]),而递归方案可能保留null。 - 性能对比:
- 小数组:递归方案可读性高。
- 大数组:迭代方案更稳定,或直接使用原生
flat(V8引擎高度优化)。
- 现代浏览器中优先使用
flat:// 最佳实践 const flattened = arr.flat(Infinity);
总结
数组扁平化需根据场景选择方案:浅层扁平化用arr.flat(depth),深层嵌套考虑迭代方案,函数式编程偏好递归实现。注意测试边界case(如空数组、非数组输入),并避免在性能敏感场景频繁创建中间数组。