Array.prototype.flatMap()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.
flatMap()
方法对数组中的每个元素应用给定的回调函数,然后将结果展开一级,返回一个新数组。它等价于在调用 map()
方法后再调用深度为 1 的 flat()
方法(arr.map(...args).flat()
),但比分别调用这两个方法稍微更高效一些。
尝试一下
语法
flatMap(callbackFn)
flatMap(callbackFn, thisArg)
参数
callbackFn
-
一个在数组的每个元素上执行的函数。它应该返回一个包含新数组元素的数组,或是要添加到新数组中的单个非数组值。该函数将被传入以下参数:
thisArg
可选-
在执行
callbackFn
时用作this
的值。参见迭代方法。
返回值
一个新的数组,其中每个元素都是回调函数的结果,并且被展开一级。
描述
flatMap()
方法是一个迭代方法。有关回调函数的详细说明,请参见 Array.prototype.map()
。flatMap()
方法等同于调用 map(callbackFn, thisArg)
后再调用 flat(1)
——对于每个元素,它都会生成一个新元素数组,并将生成的数组连接起来形成一个新数组。
flatMap()
方法是通用的。它只需要 this
值具有 length
属性和整数键属性即可。但是,如果要展开从回调函数 callbackFn
返回的值,则该值必须是数组。
替代方案
预分配数组并显式迭代
const arr = [1, 2, 3, 4];
arr.flatMap((x) => [x, x * 2]);
// 等价于
const n = arr.length;
const acc = new Array(n * 2);
for (let i = 0; i < n; i++) {
const x = arr[i];
acc[i * 2] = x;
acc[i * 2 + 1] = x * 2;
}
// [1, 2, 2, 4, 3, 6, 4, 8]
需要注意的是,在这种特定情况下,flatMap
方法的性能比 for 循环要慢——因为需要创建临时数组并进行垃圾回收,同时返回的数组不需要经常调整大小。但是,在注重灵活性和可读性的情况下,flatMap
仍可能是正确的解决方案。
示例
map() 与 flatMap()
const arr1 = [1, 2, 3, 4];
arr1.map((x) => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap((x) => [x * 2]);
// [2, 4, 6, 8]
// 只有一层被展平
arr1.flatMap((x) => [[x * 2]]);
// [[2], [4], [6], [8]]
虽然上面的示例可以通过使用 map()
方法自行实现,但下面的示例更好地展示了 flatMap()
方法的用法。
让我们从一组句子中生成单词列表。
const arr1 = ["it's Sunny in", "", "California"];
arr1.map((x) => x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]
arr1.flatMap((x) => x.split(" "));
// ["it's","Sunny","in", "", "California"]
请注意,输出列表长度可能与输入列表长度不同。
在 map()
方法过程中添加和删除元素
flatMap
方法可以用作在 map
方法中添加和删除元素(修改元素数量)的方法。换句话说,它允许你将一些项处理为另一些项(通过单独处理每个输入项),而不总是一对一的。在这个意义上,它的作用类似于 filter 的相反操作。如果要保留该项,则返回一个包含该项的单元素数组,如果要添加元素,则返回一个包含多个元素的数组,如果要删除该项,则返回一个空数组。
// 假设我们想要删除所有负数,并将奇数拆分成偶数和 1
const a = [5, 4, -3, 20, 17, -33, -4, 18];
// |\ \ x | | \ x x |
// [4,1, 4, 20, 16, 1, 18]
const result = a.flatMap((n) => {
if (n < 0) {
return [];
}
return n % 2 === 0 ? [n] : [n - 1, 1];
});
console.log(result); // [4, 1, 4, 20, 16, 1, 18]
在稀疏数组上使用 flatMap()
callbackFn
不会被源数组中的空槽调用,因为 map()
不会调用,而 flat()
将忽略返回数组中的空槽。
console.log([1, 2, , 4, 5].flatMap((x) => [x, x * 2])); // [1, 2, 2, 4, 4, 8, 5, 10]
console.log([1, 2, 3, 4].flatMap((x) => [, x * 2])); // [2, 4, 6, 8]
在非数组对象上调用 flatMap()
flatMap()
方法读取 this
的 length
属性,然后访问每个整数索引。如果回调函数的返回值不是数组,则始终直接将其附加到结果数组的末尾。
const arrayLike = {
length: 3,
0: 1,
1: 2,
2: 3,
};
console.log(Array.prototype.flatMap.call(arrayLike, (x) => [x, x * 2]));
// [1, 2, 2, 4, 3, 6]
// 回调函数返回的类数组对象不会被展平
console.log(
Array.prototype.flatMap.call(arrayLike, (x) => ({
length: 1,
0: x,
})),
);
// [ { '0': 1, length: 1 }, { '0': 2, length: 1 }, { '0': 3, length: 1 } ]
规范
Specification |
---|
ECMAScript Language Specification # sec-array.prototype.flatmap |
浏览器兼容性
BCD tables only load in the browser