展开嵌套数组
flat
该方法会按照一个
可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
它的语法是:
var newArray = arr.flat(depth)
其中depth是指定要提取嵌套数组的结构深度,默认值为 1。
let arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
let arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
1
2
3
4
5
6
7
2
3
4
5
6
7
some + concat + apply
apply() 方法调用一个具有给定
this值的函数,以及作为一个数组(或类似数组对象)提供的参数,语法如下:
func.apply(thisArg, [argsArray])
1
解决办法如下:
function flatten(arr) {
while (arr.some(item => Array.isArray(item))){
arr = [].concat.apply([], arr);
}
return arr;
}
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
console.log(flatten(arr))
// [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
concat 的作用是把参数中的数组项合并到一个结果数组中去,如下:
[].concat(1,[2,3],[4])
// [1,2,3,4]
1
2
2
而 some 可以帮我们判断当前数组下面还有没有数组,所以这个方法解释起来就是:
如果数组里面还包含数组,就创建一个空数组,将当前数组作为concat的参数传进去,赋值给当前数组,然后再判断新的数组内是否还有数组。
为什么不用 [].concat(arr) ,而是要用 [].concat.apply([], arr) 呢?
这样做的原因是为了将数组作为concat的参数传进去,这样做看起来就像 [].concat(1,[2,3],4) ,而不是 [].concat([1,[2,3],4]) ,从而能起到合并数组的作用。当然了,...(展开运算符)也能起到同样的作用,所以可以改写为如下函数:
function flatten(arr) {
while (arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
}
var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
console.log(flatten(arr))
// [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
总结该函数核心理念如下:
将数组各项
展开传入concat中,递归判断,不断展开,直到子项没有数组项为止。
reduce
对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
同理,我们可以利用reduce提供的累加来展开嵌套数组
let arr = [1, 2, '3js', [4, 5, [6], [7, 8, [9, 10, 11], null, 'abc'], {age: 12}, [13, 14]], '[]'];
function flatten(arr) {
if(Array.isArray(arr)) {
return arr.reduce((prev, cur) => {
// 如果遍历的当前项是数组,再迭代展平
return Array.isArray(cur) ? prev.concat(flatten(cur)) : prev.concat(cur)
}, [])
} else {
throw new Error(arr + ' is not array')
}
}
console.log(flatten(arr));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
← 两个数组取相同、不同项 数组去除无效值 →