展开嵌套数组

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

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

concat 的作用是把参数中的数组项合并到一个结果数组中去,如下:

[].concat(1,[2,3],[4])
// [1,2,3,4]
1
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

总结该函数核心理念如下:

将数组各项展开传入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
上次更新: 4/23/2019, 11:52:30 AM