1. 程式人生 > 其它 >淺析Array新特性flat()與flatMap()、為什麼引入flatMap及array.flatMap()的工作原理

淺析Array新特性flat()與flatMap()、為什麼引入flatMap及array.flatMap()的工作原理

  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]]