1 背景
不知道老鐵們有沒有遇到過一道面試題:如何將一個多維數組展開成一個一維數組?當時我遇到的時候還不瞭解flat這個神奇的方法,用了最傳統的解決方法進行解決。javascript
const flatten = arr => arr.toString().split(',').map(item => +item); const arr = [1, 2, [3, 4, [5, 6]]]; console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ] 複製代碼
上述方法是否是很神奇,會將多層級的數組展開成爲一個層級,可是該方式其實存在很大問題的,下面讓咱們一塊兒看看這些問題。html
- 無論多少層級都會展開爲一個層級;
- 處理後的結果其實都是字符串,須要後續再轉換爲原來的類型。
正是基於這個契機,發現了ES6新增了flat函數,這個函數天生就是爲數據扁平化處理而生的。java
2 flat基礎
flat()
方法會按照一個可指定的深度遞歸遍歷數組,並將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。git
- flat方法的用法以下所示:
const newArray = arr.flat([depth]) 複製代碼
- 小試牛刀
const arr = [1, 2, [3, 4, [5, 6]]]; console.log(arr.flat(1)); // [ 1, 2, 3, 4, [ 5, 6 ] ] console.log(arr.flat(2)); // [ 1, 2, 3, 4, 5, 6 ] 複製代碼
3 實現
flat這麼香,那麼咱們是否能夠本身實現一個呢?實現該方法的方式有不少,下面就讓咱們一塊兒看看這五種方式。(注:這五種方式試MDN上給出的替代方案)github
3.1 使用reduce和concat
該方式實現起來雖然很簡單,可是存在一個很大的缺陷:只能展開一層,對於多層的狀況將無能爲力。其思想總結起來爲如下兩個步驟:面試
- 利用reduce函數去依次處理每一個數組中的元素;
- 利用concat將當前的數組元素(值或子數組)添加到結果數組中。
// 使用reduce和concat
Array.prototype.flat1 = function () {
return this.reduce((acc, val) => acc.concat(val), []);
}
複製代碼
3.2 使用reduce + concat + isArray + recursivity
該方式已經具有展開多層的能力了,其實現思想可總結爲如下幾點:數組
- 利用reduce函數去依次處理每一個數組中的元素;
- 利用concat將當前元素添加到結果數組中;
- 利用isArray判斷當前數組中的元素是否是一個數組;
- 利用遞歸思想展開多層級的數組。
// 使用reduce + concat + isArray +recursivity
Array.prototype.flat2 = function (deep = 1) {
const flatDeep = (arr, deep = 1) => {
return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice();
}
return flatDeep(this, deep);
}
複製代碼
3.3 使用forEach + concat + isArray +recursivity
該方式與上述方式很相似,可以設定層級展開,只是遍歷數組由reduce轉換爲forEach。函數
// 使用forEach + concat + isArray +recursivity
// forEach 遍歷數組會自動跳過空元素
Array.prototype.flat3 = function (deep = 1) {
const result = [];
(function flat(arr, deep) {
arr.forEach((item) => {
if (Array.isArray(item) && deep > 0) {
flat(item, deep - 1);
} else {
result.push(item);
}
})
})(this, deep);
return result;
}
複製代碼
3.4 使用for of + concat + isArray +recursivity
該方式與上述方式很相似,可以設定層級展開,只是遍歷數組利用了for of方法post
// 使用for of + concat + isArray +recursivity
// for of 遍歷數組會自動跳過空元素
Array.prototype.flat4 = function (deep = 1) {
const result = [];
(function flat(arr, deep) {
for(let item of arr) {
if (Array.isArray(item) && deep > 0) {
flat(item, deep - 1);
} else {
// 去除空元素,由於void 表達式返回的都是undefined,不適用undefined是由於undefined在局部變量會被重寫
item !== void 0 && result.push(item);
}
}
})(this, deep);
return result;
}
複製代碼
3.5 使用堆棧stack
該方式主要利用堆棧的思想,將一個多層數組所有展開爲一層。其思想可總結爲如下幾個步驟:this
- 將要處理的數組放到一個棧中處理;
- 從棧頂取出元素,判斷該元素類型,若爲數組,則將該數組展開再放回棧頂;若爲普通元素則將其放到結果中;
- 循環遍歷,至到棧爲空。
// 使用堆棧stack
Array.prototype.flat5 = function() {
const stack = [...this];
const result = [];
while (stack.length > 0) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next);
} else {
result.push(next);
}
}
// 反轉恢復原來順序
return result.reverse();
}
複製代碼
1.若是以爲這篇文章還不錯,來個分享、點贊吧,讓更多的人也看到