array.map() 是一个非常有用的映射函数:它接收一个数组和一个映射函数,然后返回一个新的映射数组。
但是它只能一对一的映射。现在有一个替代 array.map() 的方法:array.flatMap(),这个方法给了我们映射的能力,同时也可以在生成的映射数组中删除,甚至添加新的项目。
一、更加智能的映射器:为什么引入 flatMap
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
对于需要一对一映射的情况,也就是说,映射后的数组与原始数组的项数相同,array.map() 的效果非常好。
但如果我们需要将一个数组的数字翻倍,同时跳过为 1 的项,该怎么办?
直接使用 array.map() 是不可能的,因为该方法总是创建一个映射的数组,其项数与原数组相同。但是我们可以使用 array.map()和 array.filter() 的组合:
const map1 = array1
.filter(x => x !== 1)
.map(x => x * 2);
使用 map 和 filter 结合的方式固然可以解决我们的需求,但多个方法的结合让代码看起来不那么简洁易读,有没有更简短的方式来实现呢?
答案是肯定的。使用 flatMap 方法,flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为 1 的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
const array1 = [1, 4, 9, 16];
const map1 = array1.flatMap(x => x === 1? [] :[ x*2 ])
console.log(map1);
// expected output: Array [8, 18, 32]
flatMap 能用于在map期间增删项目(也就是修改items的数量)。换句话说,它允许你遍历很多项使之成为另一些项(靠分别把它们放进去来处理),而不是总是一对一。
从这个意义上讲,它的作用类似于 filter的对立面。只需返回一个1项元素数组以保留该项,返回一个多元素数组以添加项,或返回一个0项元素数组以删除该项。
接着,我们来更详细地看看 array.flatMap() 是如何工作的。
二、array.flatMap() 详解
array.flatMap() 函数接受一个回调函数作为参数,并返回一个新的映射数组
const mappedArray = array.flatMap((item, index, origArray) => {
// ...
return [value1, value2, ..., valueN];
}[, thisArg]);
回调函数在原数组中的每个iteam上被调用,有3个参数:当前项、索引和原数组。然后,回调函数返回的数组被扁平化了1层,得到的项目被添加到映射的数组中。
此外,该方法还接受第二个可选参数,表示回调内部的 this 值。
1、使用 array.flatmap()最简单的方法是将包含项目的数组扁平化
const arrays = [[2, 4], [6]];
const flatten = arrays.flatMap(item => item);
console.log(flatten); // [2, 4, 6]
2、但是 array.flatMap() 除了简单的扁平化之外,还可以做更多的事情。通过控制从回调中返回的数组项的数量:
(1)通过返回一个空数组从结果数组中删除该项
(2)通过返回一个带有一个新值的数组 [newValue] 来修改映射的项
(2)通过返回一个包含多个值的数组来添加新项: [newValue1, newValue2, ...]
例如,可以通过将项目加倍来创建一个新的数组,但同时也要删除 0。
const numbers = [0, 3, 6];
const doubled = numbers.flatMap(number => {
return number === 0 ? [] : [2 * number];
});
console.log(doubled); // [6, 12]
3、现在,我们来看下它是怎么工作的:
(1)如果当前项为 0,回调函数返回一个空数组 [],这意味着当被扁平化时,空数组 [] 没有提供任何值
(2)如果当前迭代项非零,则返回 [2 * number],当扁平[2 * number]数组时,结果数组中只添加 2 * number
4、你也可以使用 array.flatMap()来增加映射的数组中的项目数量。
例如下面的代码片段通过添加两倍和三倍的数字将一个数字数组映射到一个新数组
const numbers = [1, 4];
const trippled = numbers.flatMap(number => {
return [number, 2 * number, 3 * number];
});
console.log(trippled); // [1, 2, 3, 4, 8, 12]
5、总结
如果你想把一个数组映射到一个新的数组中,同时又能控制你想在新的映射数组中添加多少项,那么 array.flatMap() 方法就是一个好办法。
array.flatMap(callback) 的回调函数被调用,有3个参数:当前迭代的项、索引和原始数组。然后,从回调函数返回的数组在1层深处被扁平化,得到的项目被插入到所产生的映射数组中。
三、array新特性 flat() 与 flatMap()
flat()
和flatMap()
本质上就是是归纳(reduce) 与 合并(concat)的操作。
1、flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
flat() 方法最基本的作用就是数组降维
var arr1 = [1, 2, [3, 4]];
arr1.flat(); // [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(); // [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2); // [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity); // [1, 2, 3, 4, 5, 6]
2、flatMap() 方法:首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。
它与 map 和 深度值 1 的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。 这里我们拿map方法与flatMap方法做一个比较。
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]); // [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]); // [2, 4, 6, 8] 自动压平了 1 层
// 只会将 flatMap 中的函数返回的数组 “压平” 一层
arr1.flatMap(x => [[x * 2]]); // [[2], [4], [6], [8]]