今天看到一篇文章,其中講解了數組扁平化處理的多種方法,個人覺得還是有點意思,現詳細講解幾種實現的方法。
- 使用forEach
function flatten1(arr){
let res = [];
arr.forEach((val)=>{
res.push( ...( Array.isArray(val) ? flatten1(val) : [val] ) );
});
return res;
}
這個方法沒啥好說的,運用了遞歸,同時使用了...
操作符將數組進行了展開
- 使用reduce
function flatten2(arr){
return arr.reduce((prev, curr)=>{
return prev.concat( Array.isArray(curr) ? flatten2(curr) : curr );
}, [] );
}
這個方法也很好理解,就是使用reduce的特性,同時使用了遞歸
- 使用some
function flatten3(arr){
while( arr.some( val=>Array.isArray(val) ) ){
arr = [].concat(...arr);
}
return arr;
}
該方法雖然沒有前面幾種方法實現的n那麼優雅,但是還是給了我一些驚喜。因爲猛一看,我竟然沒發現實現的具體原理。
直到我輸入了下面的測試代碼,我才明白:
var a = [].concat(1,2, [3,4]);
var b = [].concat(1,2,[ [5, 6] , 7 ]);
console.log(a); //[1, 2, 3, 4]
console.log(b) ;//[1, 2, Array(2), 7]
也就是說concat中跟隨的項可以包含一維數組,而且一維數組會被展開,但二維數組就不可以。這和我預期的還是不一樣的。所以還是基礎知識不夠牢靠啊!
後來查閱了一下MDN,發現這麼一個注意
數字和布爾(不是String,Number 和 Boolean 對象):concat將字符串和數字的值複製到新數組中。
注意:數組/值在連接時保持不變。此外,對於新數組的任何操作(僅當元素不是對象引用時)都不會對原始數組產生影響,反之亦然。
也就是說concat對於對象的拷貝是淺拷貝,舉個列子:
var a = [{a:1}, 2], b = [];
var c = a.concat(b);
c[0].a = 3;
console.log( a[0].a ); //3
可以看到我們在鏈接後的新對象c中更改了數組中的第一項的屬性a的值,結果這個更改在數組a的第一項也發生了。