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.
Array
实例的 flatMap()
方法返回一个新数组,该数组通过将给定的回调函数应用于数组的每个元素,然后将结果展平一级而形成。它与 map()
后跟深度 1 (arr.map(...args).flat()
) 的 flat()
相同,但比分别调用这两个方法稍微高效一些。
¥The flatMap()
method of Array
instances returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level. It is identical to a map()
followed by a flat()
of depth 1 (arr.map(...args).flat()
), but slightly more efficient than calling those two methods separately.
Try it
语法
参数
返回值
描述
¥Description
flatMap()
方法是 迭代法 方法。回调函数的详细说明参见 Array.prototype.map()
。flatMap()
方法与 map(callbackFn, thisArg)
后跟 flat(1)
相同 - 对于每个元素,它生成一个新元素数组,并将结果数组连接在一起形成一个新数组。请阅读 迭代法 部分,了解有关这些方法一般如何工作的更多信息。
¥The flatMap()
method is an iterative method. See Array.prototype.map()
for a detailed description of the callback function. The flatMap()
method is identical to map(callbackFn, thisArg)
followed by flat(1)
— for each element, it produces an array of new elements, and concatenates the resulting arrays together to form a new array. Read the iterative methods section for more information about how these methods work in general.
flatMap()
方法是 generic。它只期望 this
值具有 length
属性和整数键控属性。但是,如果要展平,从 callbackFn
返回的值必须是数组。
¥The flatMap()
method is generic. It only expects the this
value to have a length
property and integer-keyed properties. However, the value returned from callbackFn
must be an array if it is to be flattened.
选择
¥Alternative
预分配和显式迭代
¥Pre-allocate and explicitly iterate
const arr = [1, 2, 3, 4];
arr.flatMap((x) => [x, x * 2]);
// is equivalent to
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
仍然可能是正确的解决方案。
¥Note that in this particular case the flatMap
approach is slower than the
for-loop approach — due to the creation of temporary arrays that must be
garbage collected, as well as the return array not needing to be frequently
resized. However, flatMap
may still be the correct solution in cases where
its flexibility and readability are desired.
示例
map() and 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]
// only one level is flattened
arr1.flatMap((x) => [[x * 2]]);
// [[2], [4], [6], [8]]
虽然上述内容可以通过使用地图本身来实现,但这里有一个例子可以更好地展示 flatMap()
的使用。
¥While the above could have been achieved by using map itself, here is an example that
better showcases the use of flatMap()
.
让我们从句子列表中生成单词列表。
¥Let's generate a list of words from a list of sentences.
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"]
请注意,输出列表长度可以与输入列表长度不同。
¥Notice, the output list length can be different from the input list length.
用于在 map() 期间添加和删除项目
¥For adding and removing items during a map()
flatMap
可以用作 map
期间添加和删除项目(修改项目数量)的一种方式。换句话说,它允许你将许多项目映射到许多项目(通过单独处理每个输入项目),而不是始终一对一。从这个意义上说,它的工作原理与 filter 相反。返回 1 元素数组以保留项目,返回多元素数组以添加项目,或返回 0 元素数组以删除项目。
¥flatMap
can be used as a way to add and remove items (modify the number of
items) during a map
. In other words, it allows you to map many items to
many items (by handling each input item separately), rather than always
one-to-one. In this sense, it works like the opposite of filter.
Return a 1-element array to keep the item, a multiple-element array to add items, or a
0-element array to remove the item.
// Let's say we want to remove all the negative numbers
// and split the odd numbers into an even number and a 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]
使用 callbackFn 的第三个参数
¥Using the third argument of callbackFn
如果你想访问数组中的另一个元素,特别是当你没有引用该数组的现有变量时,array
参数非常有用。以下示例首先使用 filter()
提取操作站,然后使用 flatMap()
创建一个新数组,其中每个元素包含一个站及其下一个站。在最后一个站点上,它返回一个空数组以将其从最终数组中排除。
¥The array
argument is useful if you want to access another element in the array, especially when you don't have an existing variable that refers to the array. The following example first uses filter()
to extract operational stations and then uses flatMap()
to create a new array where each element contains a station and its next station. On the last station, it returns an empty array to exclude it from the final array.
const stations = ["New Haven", "West Haven", "Milford (closed)", "Stratford"];
const line = stations
.filter((name) => !name.endsWith("(closed)"))
.flatMap((name, idx, arr) => {
// Without the arr argument, there's no way to easily access the
// intermediate array without saving it to a variable.
if (idx === arr.length - 1) return []; // last station has no next station
return [`${name} - ${arr[idx + 1]}`];
});
console.log(line); // ['New Haven - West Haven', 'West Haven - Stratford']
array
参数不是正在构建的数组 - 无法从回调函数访问正在构建的数组。
¥The array
argument is not the array that is being built — there is no way to access the array being built from the callback function.
在稀疏数组上使用 flatMap()
¥Using flatMap() on sparse arrays
不会为源数组中的空槽调用 callbackFn
,因为 map()
不会,而 flat()
会忽略返回数组中的空槽。
¥The callbackFn
won't be called for empty slots in the source array because map()
doesn't, while flat()
ignores empty slots in the returned arrays.
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()
¥Calling flatMap() on non-array objects
flatMap()
方法读取 this
的 length
属性,然后访问键为小于 length
的非负整数的每个属性。如果回调函数的返回值不是数组,则总是直接追加到结果数组中。
¥The flatMap()
method reads the length
property of this
and then accesses each property whose key is a nonnegative integer less than length
. If the return value of the callback function is not an array, it is always directly appended to the result array.
const arrayLike = {
length: 3,
0: 1,
1: 2,
2: 3,
3: 4, // ignored by flatMap() since length is 3
};
console.log(Array.prototype.flatMap.call(arrayLike, (x) => [x, x * 2]));
// [1, 2, 2, 4, 3, 6]
// Array-like objects returned from the callback won't be flattened
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