JavaScript数组扁平化七种实现方案解析
本文系统总结了JavaScript中实现数组扁平化的七种常用方法,涵盖普通递归、reduce累加、ES6 flat、扩展运算符、广度优先搜索(BFS)、深度优先搜索(DFS)以及Lodash库。文章详细对比了各方法的代码实现、优缺点及适用场景,帮助开发者根据性能、兼容性和代码简洁性需求选择最佳方案。
前言
数组扁平化是前端开发中的常见面试题,也是日常编程中的基础操作,旨在将多维数组转换为一维数组。虽然多数开发者能给出一种解法,但面对要求提供多种实现的情况时,往往难以应对。本文将汇总几种主流的数组扁平化实现方式,供读者参考。
1. 普通递归方法
- 大多数开发者首先想到的方案是使用递归函数。该算法遍历数组元素,判断其是否为数组类型;若是,则对子数组递归执行扁平化操作,并将结果合并至最终的一维数组中。具体实现如下:
let arr = [1,2,[3,4,[5,6]]]
function flattenArray(arr) {
let result = []
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flattenArray(arr[i]));
} else {
result.push(arr[i])
}
}
return result
}
console.log(flattenArray(arr)); // [ 1, 2, 3, 4, 5, 6 ]
2. reduce() 方法
- 利用
Array.prototype.reduce()的累加器特性,遍历数组并将子数组扁平化后的结果合并至最终的一维数组。这本质上仍是递归逻辑,但相较于使用for循环,该方法借助reduce函数使代码更为简洁。
let arr = [1,2,[3,4,[5,6,[7,8]]]]
function flattenWithReduce(arr) {
return arr.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flattenWithReduce(val) : [val]),
[]
);
}
console.log(flattenWithReduce(arr)) // [1, 2, 3, 4, 5, 6, 7, 8]
优点:代码可读性强,逻辑清晰,无需额外创建函数闭包。 缺点:处理极深嵌套结构时,性能可能不及原生flat()方法。
3. Array.prototype.flat()
- ES6标准引入了
flat()方法,可直接对数组进行扁平化处理,并支持指定扁平化的层级深度。
let arr = [1,2,[3,4,[5,6,[7,8,[9]]]]]
function flattenWithFlat(arr) {
return arr.flat(Infinity) // Infinity表示完全扁平化所有层级
}
console.log(flattenWithFlat(arr)) // [1,2,3,4,5,6,7,8,9]
优点:语法简洁高效,原生支持,适用于现代浏览器环境。 缺点:旧版浏览器不支持,需配合polyfill或其他兼容方案使用。
4. 扩展运算符与concat
- 结合扩展运算符(...)与
concat(),逐步展开嵌套数组结构。
let arr = [1,2,[3,[4],[5,6,[7,8,[9]]]]]
function flattenWithSpread(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
console.log(flattenWithSpread(arr)); // [1,2,3,4,5,6,7,8,9]
优点:代码相对简洁,易于理解。 缺点:循环执行次数取决于数组嵌套深度,整体效率相对较低。
5. 广度优先搜索与队列
- 该方法采用广度优先搜索(BFS)策略。首先创建队列并将原数组作为初始节点入队。随后进入循环,只要队列非空,便从头部取出当前层级的所有元素(子数组或值)。若元素为数组,则将其内部元素逐个加入队列尾部;若非数组,则直接加入结果数组。循环直至队列为空,此时结果数组包含所有展开的一维元素。
let arr = [1,2,[3,[4],[5,6,[7,8,[9]]]]]
function flattenWithBFS(arr) {
const queue = [arr] // 创建队列,初始化为待处理的数组
const result = []
while (queue.length > 0) {
const levelItems = queue.shift() // 取出队列首部的一层元素
for (const item of levelItems) { // 遍历当前层级的每个元素
if (Array.isArray(item)) {
queue.push(item);
} else {
result.push(item)
}
}
}
return result
}
console.log(flattenWithBFS(arr)) // [1,2,3,4,5,6,7,8,9]
优点:
- 空间效率较高:通过队列结构进行层次遍历,确保在有限循环次数内完成任意深度嵌套数组的扁平化。
- 无需递归调用栈:相比递归方法,此方案避免了因深层嵌套导致的栈溢出风险。
缺点:
- 时间复杂度:虽优于扩展运算符结合concat()的方法,但在极端情况(如极深且宽的树形结构)下,仍需多次迭代才能完全扁平化数组。
- 代码相对复杂:相较于简单的扩展运算符与concat()结合方式,此方法涉及队列操作,理解成本稍高。
6. 深度优先搜索与堆栈
- 该方法利用堆栈数据结构进行深度优先搜索(DFS)。首先将待处理的原数组转换为堆栈,并创建空结果数组。在循环中,只要堆栈非空,便从顶部取出当前元素。若元素为数组,则将其所有元素压入堆栈;若非数组,则直接添加至结果数组头部。此过程不断深入嵌套数组最底层,再逐层返回,直至堆栈为空。
let arr = [1,2,[3,[4],[5,6,[7,8,[9]]]]]
function flattenWithDFS(arr) {
const stack = [...arr] // 将原数组转换为堆栈
const result = []
while (stack.length > 0) { // 当堆栈中有待处理元素时
const current = stack.pop() // 取出堆栈顶部的元素
if (Array.isArray(current)) {
stack.push(...current) // 将其所有元素压入堆栈
} else {
result.unshift(current) // 否则将非数组元素添加到结果数组的开头
}
}
return result
}
console.log(flattenWithDFS(arr)); // [1,2,3,4,5,6,7,8,9]
优点:
- 递归思想简化实现:深度优先搜索天然适用于解决递归问题,此方法避免了显式递归调用,但仍保持递归处理的核心思想。
- 无需额外空间复杂度:相比广度优先搜索需队列保存每一层级数据,深度优先搜索仅需一个堆栈,对内存资源有限的场景更为友好。
缺点:
- 遍历顺序:深度优先搜索可能导致扁平化后的一维数组中元素顺序与原始嵌套数组的层级顺序不一致。
- 栈溢出风险:面对极深嵌套数组时,由于使用堆栈模拟递归,可能触及JavaScript堆栈大小限制,导致栈溢出错误。
7. lodash库的_.flattenDeep()
- lodash库提供了现成的
_.flattenDeep()方法,可处理任意深度的嵌套数组。
import _ from 'lodash'
let arr = [1,2,[3,[4],[5,6,[7,8,[9]]]]]
const flattenedArr = _.flattenDeep(nestedArr)
console.log(flattenedArr)
优点:第三方库封装,功能强大且经过优化,适用于各种复杂场景。 缺点:增加项目依赖,不适合仅需简单扁平化且关注性能与体积的应用场景。
以上介绍了七种常见的数组扁平化方式。掌握这些方法后,应对相关面试或开发需求将更为从容。本文主要聚焦于方法总结,未深入探讨应用场景,感兴趣者可自行搜索。如有其他扁平化方法,欢迎在评论区补充。
到此这篇关于JS实现数组扁平化的方法总结的文章就介绍到这了,更多相关JS数组扁平化内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
