悠悠楠杉
如何用JavaScript实现数组扁平化:从基础到高阶实践
如何用JavaScript实现数组扁平化:从基础到高阶实践
一、理解数组扁平化的核心概念
数组扁平化(Flatten Array)是指将多维数组转换为一维数组的过程。在实际开发中,我们常遇到嵌套数组结构的数据处理需求,比如:
javascript
const nestedArray = [1, [2, 3], [4, [5, 6]]];
// 扁平化后 => [1, 2, 3, 4, 5, 6]
为什么需要扁平化?
- 数据清洗时简化结构
- 便于进行统一的数组操作(如排序、过滤)
- 符合后端接口的数据格式要求
- 提高数据处理效率
二、原生JS实现方案对比
1. 基础递归实现
javascript
function flatten(arr) {
let result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result = result.concat(flatten(item));
} else {
result.push(item);
}
});
return result;
}
2. 使用reduce优化递归
javascript
function flatten(arr) {
return arr.reduce((acc, cur) =>
acc.concat(Array.isArray(cur) ? flatten(cur) : cur), []);
}
3. ES2019原生flat方法
javascript
// 指定展开深度
const flattened = nestedArray.flat(Infinity);
4. 利用扩展运算符
javascript
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
三、性能考量与边界处理
性能对比(10,000个元素测试)
- 递归方案:约12ms
- while循环方案:约8ms
- flat方法:约5ms
需要注意的特殊情况
javascript
// 稀疏数组处理
flatten([1, , 3]) // 应该保留空位还是过滤?
// 非数组输入
flatten({}) // 应该抛出错误还是特殊处理?
// 循环引用
const circular = [];
circular.push(circular);
flatten(circular) // 最大调用栈问题
四、实际应用场景解析
案例1:处理API返回的嵌套数据
javascript
const apiResponse = {
data: [
{ id: 1, tags: ['js', 'web'] },
{ id: 2, tags: ['node', 'backend'] }
]
};
const allTags = flatten(apiResponse.data.map(item => item.tags));
// => ['js', 'web', 'node', 'backend']
案例2:多级分类列表展开
javascript
const categoryTree = [
'电子产品',
['手机', ['智能机', '功能机']],
['电脑', ['笔记本', '台式机']]
];
const flatCategories = flatten(categoryTree);
// 生成面包屑导航或全文搜索索引
五、进阶技巧与优化方案
1. 添加深度控制参数
javascript
function flatten(arr, depth = Infinity) {
return depth > 0
? arr.reduce((acc, val) =>
acc.concat(Array.isArray(val)
? flatten(val, depth - 1)
: val), [])
: arr.slice();
}
2. 类型安全的扁平化
javascript
function flatten(arr, typeFilter) {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) {
return acc.concat(flatten(val, typeFilter));
}
return typeFilter ? (typeof val === typeFilter ? acc.concat(val) : acc)
: acc.concat(val);
}, []);
}
// 只扁平化数字类型
flatten([1, ['a', 2], 3], 'number'); // => [1, 2, 3]
3. 生成器实现懒加载
javascript
function* flattenGenerator(arr) {
for (const item of arr) {
if (Array.isArray(item)) {
yield* flattenGenerator(item);
} else {
yield item;
}
}
}
// 使用示例
const gen = flattenGenerator([1, [2, [3]]]);
console.log([...gen]); // => [1, 2, 3]
六、与其他数组操作的组合应用
1. 扁平化后去重
javascript
const uniqueFlatten = arr => [...new Set(flatten(arr))];
uniqueFlatten([[1, 2], [2, [3]]]); // => [1, 2, 3]
2. 配合map使用
javascript
const data = [[{x:1}, {x:2}], [{x:3}]];
flatten(data.map(obj => obj.x));
// 先map再扁平化比先扁平化再map性能更好
3. 条件扁平化
javascript
function conditionalFlatten(arr, predicate) {
return arr.reduce((acc, val) => {
if (Array.isArray(val) && predicate(val)) {
return acc.concat(conditionalFlatten(val, predicate));
}
return acc.concat(val);
}, []);
}
// 只展开包含数字的数组
conditionalFlatten(
[1, ['a', 2], [3, [4]]],
arr => arr.some(x => typeof x === 'number')
);