數(shù)組扁平化定義:在前端項目開發(fā)過程中仰坦,偶爾會出現(xiàn)層疊數(shù)據(jù)結(jié)構(gòu)的數(shù)組,需要把多層數(shù)組轉(zhuǎn)換為一級數(shù)組(即提取嵌套數(shù)組元素最終合并為一個數(shù)組)计雌,使其內(nèi)容合并并且展開缎岗。
- 需求:多維數(shù)組 => 一維數(shù)組
let arr = [1, 2, [3, [4, 5, [6,7]]], 8]; // -> [1, 2, 3, 4, 5, 6, 7, 8]
let str = JSON.stringify(arr);
- 方法一:調(diào)用ES6中的flat方法
arr = arr.flat(Infinity);
//不傳參數(shù)時,默認“拉平”一層白粉;傳入一個整數(shù)參數(shù)传泊,整數(shù)即“拉平”的層數(shù);
//Infinity 關(guān)鍵字作為參數(shù)時鸭巴,無論多少層嵌套眷细,都會轉(zhuǎn)為一維數(shù)組
//傳入 <=0 的整數(shù)將返回原數(shù)組,不“拉平”
//如果原數(shù)組有空位鹃祖,flat()方法會跳過空位
- 手寫一個數(shù)組扁平化flat方法
思路:
1溪椎、遍歷數(shù)組的每一個元素;
2恬口、判斷元素是否為數(shù)組校读;
3、將是數(shù)組的元素進行展開祖能。
遍歷數(shù)組的方案:
for循環(huán)
for...of
for...in
forEach()
entries()
keys()
values()
reduce()
map()
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "小馬同學" }];
//for循環(huán)遍歷
for (var i = 0; i < arr.length; i++){
console.log(arr[i]);
}
//for...of遍歷
for (let item of arr) {
console.log(item)
}
//for...in遍歷
for (let item in arr) {
console.log(arr[item]);
}
//forEach遍歷
arr.forEach(value = >{
console.log(value);
});
// entries()遍歷
for (let [index, value] of arr.entries()) {
console.log(value);
}
// keys() 遍歷
for (let index of arr.keys()) {
console.log(arr[index]);
}
// values() 遍歷
for (let value of arr.values()) {
console.log(value);
}
//map() 遍歷
arr.map(value = > {
console.log(value);
}
判斷元素是否是數(shù)組的方案:
instanceof
constructor
object.prototype.toString.call
isArray
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "小馬同學" }];
arr instanceof Array; // true
arr.constructor === Array; //true
object.prototype.toString.call(arr) === '[object Array]'; //true
Array.isArray(arr); //true
instanceof 操作符是假定只有一種全局環(huán)境歉秫,如果網(wǎng)頁中包含多個框架,多個全局環(huán)境养铸,如果你從一個框架向另一個框架傳入一個數(shù)組雁芙,那么傳入的數(shù)組與在第二個框架中原生創(chuàng)建的數(shù)組分別具有各自不同的構(gòu)造函數(shù)。(所以在這種情況下會不準確)
typeof 操作符對數(shù)組取類型將返回 object
因為 constructor 可以被重寫钞螟,所以不能確保一定是數(shù)組兔甘。
//constructor重寫,判斷字符串為數(shù)組
const str = 'abc';
str.constructor = Array;
str.constructor === Array
// true
將數(shù)組元素進行展開一層的方案:
擴展運算法 + concat(concat() 方法用于合并兩個或多個數(shù)組,在拼接的過程中加上擴展運算符會展開一層數(shù)組)
concat + apply(主要是利用 apply 在綁定作用域時,傳入的第二個參數(shù)是一個數(shù)組或者類數(shù)組對象蹋半,其中的數(shù)組元素將作為單獨的參數(shù)傳給 func 函數(shù)。也就是在調(diào)用 apply 函數(shù)的過程中澡匪,會將傳入的數(shù)組一個一個的傳入到要執(zhí)行的函數(shù)中,也就是相當對數(shù)組進行了一層的展開提岔。)
toString + split(不推薦使用 toString + split 方法仙蛉,因為操作字符串是很危險的事情,如果數(shù)組中的元素所有都是數(shù)字的話碱蒙,toString + split 是可行的荠瘪,并且是一步搞定夯巷。)
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "小馬同學" }];
//擴展運算法 + concat
[ ].concat(...arr);
// concat + apply
[ ].concat.apply([ ], arr);
//以上兩種方法,輸出結(jié)果:
//[1, 2, 3, 4, 1, 2, 3, [1, 2, 3, [1, 2, 3]], 5, "string", { name: "小馬同學" }];
//toString + split
const arr2 = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]]];
arr2.toString().split(',').map(v = > parseInt(v));
//[1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3]
最終手寫的flat()方法為:
const arr = [1, 2, 3, 4, 5, [1, 2, [1, 2, 3, [4, 5]]], 6, 'flat方法', {name: '小馬同學' }];
function flat(arr){
let arrResult = [];
for(let value of arr){
if(Array.isArray(value)){
arrResult.push(...arguments.callee(value)); //遞歸
}else{
arrResult.push(value);
}
}
return arrResult;
}
console.log(flat(arr));
//[1, 2, 3, 4, 5, 1, 2, 1, 2, 3, 4, 5, 6, 'flat方法', {name: '小馬同學' }]
arguments.callee(value) = flat(value)趁餐,為了解決函數(shù)的執(zhí)行與函數(shù)名flat緊密耦合的情況。
擴展運算符是三個點(...)臀突,比較像 rest 參數(shù)的逆運算候学,作用是將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列纵散。
- 方法二:repalce + split
arr = str.replace(/(\[|\]))/g, '').split(',');
- 方法三:replace + JSON.parse
str = str.replace(/(\[|\]))/g, '');
str = '[' + str +']';
arr = JSON.parse(str);
- 方法四:普通遞歸
let result = [];
let fn = function(arr){
for(let i = 0; i < arr.length; i++){
let item = arr[i]; //重點
if(Array.isArray(arr[i])){
fn(item); //遞歸
}else{
result.push(item);
}
}
}
- 方法五:利用reduce函數(shù)迭代
const arr = [1, 2, 3, 4, 5, [1, 2, [1, 2, 3, [4, 5]]], 6, 'flat方法', {name: '小馬同學' }];
function flatten(arr){
return arr.reduce((pre,cur) =>{
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);
}
console.log(flatten(arr));
//[1, 2, 3, 4, 5, 1, 2, 1, 2, 3, 4, 5, 6, 'flat方法', {name: '小馬同學' }]
- 方法六:擴展運算符
let arr = [1, 2, 3, 4, [5, 6, [7, 8]]]; //這個方法數(shù)組中的元素只能是數(shù)字伍掀?
while (arr.some((item) => { return Array.isArray(item) })) {
arr = [].concat(…arr);
}
console.log(arr)
參考博客如下,注明一下出處濒蒋,感謝大神們甸各,希望自己可以多多練習,多多回顧:
三元博客
JS數(shù)組reduce()方法詳解及高級技巧
數(shù)組flat方法實現(xiàn)