JS:展开多维数组的 10 种方法(可控制深度)
[1, [2, 3, [4, 5, [6, 7, 8, [9, 10]]]]]
👇
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
使用
Array.prototype.flat()
方法(可控制深度)ES2019 新增了
Array.prototype.flat()
方法,该方法可以按照指定的深度将多维数组展开,然后作为一个新数组返回。深度的默认值为1
。如果想要全部展开,只需传递一个Infinity
(无穷大) 即可。console.log(sourceData.flat()) // [1, 2, 3, [4, 5, [6, 7, 8, [9, 10]]]] console.log(sourceData.flat(Infinity)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
但是 IE 浏览器并不支持此方法,所以需要进行 polyfill。但是不要担心,下面有九种 polyfill 方法供我们选择。
-
使用
for()
循环进行递归使用
for()
循环依次判断每一项是否是数组,如果是,调用此方法继续遍历,如果不是,直接添加到返回值数组中,直到全部展开。function flatByFor(arr) { const res = [] for (let i = 0; i < arr.length; i++) { Array.isArray(arr[i]) ? res.push(...flatByFor(arr[i])) : res.push(arr[i]) } return res } console.log(flatByFor(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
for()
递归增强版(可控制深度)可以将深度作为参数传递,在展开时判断是否达到指定的深度,如果达到指定的深度,则直接添加到返回值数组中,否则继续遍历。
function deepFlatByFor(arr, depth = Infinity) { const res = [] for (let i = 0; i < arr.length; i++) { Array.isArray(arr[i]) && depth > 0 ? res.push(...deepFlatByFor(arr[i], depth - 1)) : res.push(arr[i]) } return res } console.log(deepFlatByFor(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(deepFlatByFor(sourceData, 2)) // [1, 2, 3, 4, 5, [6, 7, 8, [9, 10]]]
-
使用
forEach()
进行递归和
for()
类似,只是使用Array.prototype.forEach()
方法。function flatByForEach(arr) { const res = [] arr.forEach(item => { Array.isArray(item) ? res.push(...flatByForEach(item)) : res.push(item) }) return res } console.log(flatByForEach(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
forEach()
递归增强版(可控制深度)和
for()
类似,只是使用Array.prototype.forEach()
方法。function deepFlatByForEach(arr, depth = Infinity) { const res = [] arr.forEach(item => { Array.isArray(item) && depth > 0 ? res.push(...deepFlatByForEach(item, depth - 1)) : res.push(item) }) return res } console.log(deepFlatByForEach(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(deepFlatByForEach(sourceData, 2)) // [1, 2, 3, 4, 5, [6, 7, 8, [9, 10]]]
-
使用
while()
循环配合Array.prototype.some()
判断使用
Array.prototype.some()
方法检测数组中是否还存在数组,将其作为while()
的执行条件,如果有数组可一直执行,而Array.prototype.concat()
方法可以将多个数组合并到一个数组中,所以这里我们只需要利用扩展运算符不断的将数组展开合并即可。function flatByWhileSome(arr) { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr) } return arr } console.log(flatByWhileSome(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
while()
循环配合Array.prototype.some()
增强版(可控制深度)function deepFlatByWhileSome(arr, depth = Infinity) { while (arr.some(item => Array.isArray(item)) && depth > 0) { arr = [].concat(...arr) depth-- } return arr } console.log(deepFlatByWhileSome(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(deepFlatByWhileSome(sourceData, 2)) // [1, 2, 3, 4, 5, [6, 7, 8, [9, 10]]]
-
使用
while()
循环配合Array.prototype.shift()
判断使用
shift()
方法将数组中的元素依次取出并判断是否为数组,如果是,将其展开后并再次存入,等待下一次遍历,如果不是,则将其存入返回值数组,直到全部展开。由于shift()
方法会改变原数组,所以我们需要将原数组复制一份,然后再进行遍历。function flatByWhileShift(arr) { const res = [] const stack = [...arr] // 或 arr.slice() while (stack.length) { const next = stack.shift() Array.isArray(next) ? stack.push(...next) : res.push(next) } return res } console.log(flatByWhileShift(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
使用
reduce()
配合Array.prototype.concat()
进行递归reduce()
方法可以从左到右依次对数组中的元素执行传入的函数,并返回执行结果。所以我们在传给reduce()
的函数中,将不是数组的元素直接使用concat()
方法拼接到返回值数组,将是数组的元素递归调用此方法再进行拼接。function flatByReduce(arr) { return arr.reduce((acc, cur) => { return acc.concat(Array.isArray(cur) ? flatByReduce(cur) : cur) }, []) } console.log(flatByReduce(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
reduce()
递归增强版(可控制深度)function deepFlatByReduce(arr, depth = Infinity) { return depth > 0 ? arr.reduce( (acc, cur) => acc.concat( Array.isArray(cur) ? deepFlatByReduce(cur, depth - 1) : cur ), [] ) : arr.slice() } console.log(deepFlatByReduce(sourceData)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(deepFlatByReduce(sourceData, 2)) // [1, 2, 3, 4, 5, [6, 7, 8, [9, 10]]]
参考资料:
网友评论