JavaScript進(jìn)行數(shù)組扁平化的四種方法詳解與最佳實(shí)踐
在日常開發(fā)中,我們經(jīng)常會遇到嵌套數(shù)組(nested arrays)的處理需求。例如,從 API 接口返回的數(shù)據(jù)可能包含多層結(jié)構(gòu),而我們需要將其“拍平”成一維數(shù)組以便后續(xù)操作。本文將以如下示例數(shù)據(jù)為切入點(diǎn),系統(tǒng)性地介紹四種主流的數(shù)組扁平化方法,并從語法簡潔性、執(zhí)行性能、兼容性、適用場景等多個(gè)維度進(jìn)行對比分析。
const arr = [[1, 2], [3, 4], [5, 6]]; // 目標(biāo):[1, 2, 3, 4, 5, 6]
方法 1:Array.prototype.flat()(現(xiàn)代標(biāo)準(zhǔn),推薦)
基本用法
ES2019(ECMAScript 2019)引入了 flat() 方法,專門用于數(shù)組扁平化,語法簡潔直觀:
const merged = arr.flat(); console.log(merged); // [1, 2, 3, 4, 5, 6]
深度控制
默認(rèn)只展開一層嵌套。
可通過傳入?yún)?shù)指定展開深度:
const deepArr = [[[1, 2]], [[3, 4]]]; console.log(deepArr.flat(2)); // [[1, 2], [3, 4]] console.log(deepArr.flat(Infinity)); // [1, 2, 3, 4] — 完全扁平化
優(yōu)勢
- 語義清晰:專為扁平化設(shè)計(jì),意圖明確。
- 性能良好:原生實(shí)現(xiàn),V8 等引擎高度優(yōu)化。
- 不可變性:不修改原數(shù)組,返回新數(shù)組。
注意事項(xiàng)
- 不支持 IE 和部分舊版移動端瀏覽器(需 Babel 轉(zhuǎn)譯或 polyfill)。
- 對于僅需處理單層嵌套的場景,
flat()是首選方案。
方法 2:擴(kuò)展運(yùn)算符 +concat()
實(shí)現(xiàn)方式
利用 ES6 的擴(kuò)展運(yùn)算符(spread operator)將子數(shù)組作為參數(shù)傳入 concat:
const merged = [].concat(...arr); console.log(merged); // [1, 2, 3, 4, 5, 6]
原理剖析
...arr將[[1,2], [3,4], [5,6]]展開為三個(gè)獨(dú)立參數(shù):[1,2],[3,4],[5,6]。[].concat(a, b, c)等價(jià)于合并這些數(shù)組。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 代碼簡短,一行搞定。
- 兼容 ES6+ 環(huán)境(現(xiàn)代瀏覽器和 Node.js 廣泛支持)。
缺點(diǎn):
- 存在棧溢出風(fēng)險(xiǎn):當(dāng)子數(shù)組數(shù)量極大(如 > 10?)時(shí),函數(shù)調(diào)用??赡艹鱿拗疲ㄒ?
concat接收的是展開后的參數(shù)列表)。 - 僅適用于單層嵌套,無法處理深層結(jié)構(gòu)。
適用建議:適合中小型數(shù)組、追求代碼簡潔性的場景。
方法 3:Array.prototype.reduce()
經(jīng)典寫法
const merged = arr.reduce((acc, subArr) => acc.concat(subArr), []);
性能優(yōu)化寫法(使用擴(kuò)展運(yùn)算符)
const merged = arr.reduce((acc, subArr) => [...acc, ...subArr], []);
深度解析
- 第一種寫法:每次調(diào)用
concat都會創(chuàng)建一個(gè)新數(shù)組,時(shí)間復(fù)雜度為 O(n²),大數(shù)據(jù)量下性能較差。 - 第二種寫法:雖然避免了
concat,但[...acc, ...subArr]同樣會復(fù)制整個(gè)累加器數(shù)組,內(nèi)存開銷大。
適用場景
需要兼容 ES5 或更老環(huán)境(如 IE11)。
需要在扁平化過程中加入自定義邏輯(如過濾、映射等):
arr.reduce((acc, sub) => {
return acc.concat(sub.filter(x => x > 2));
}, []);
總結(jié)
- 靈活性高,但性能較低。
- 除非有特殊需求,否則不建議在現(xiàn)代項(xiàng)目中作為首選。
方法 4:for...of循環(huán) +push(...subArr)
高性能實(shí)現(xiàn)
const merged = [];
for (const subArr of arr) {
merged.push(...subArr);
}
console.log(merged); // [1, 2, 3, 4, 5, 6]
為什么高效
- 原地操作:直接向結(jié)果數(shù)組追加元素,避免中間數(shù)組創(chuàng)建。
- 無函數(shù)調(diào)用開銷:相比
reduce或concat,循環(huán)開銷極小。 - 內(nèi)存友好:適合處理超大數(shù)組(如百萬級元素)。
注意事項(xiàng)
仍受限于擴(kuò)展運(yùn)算符的參數(shù)數(shù)量上限(理論上 V8 引擎限制約為 65535 個(gè)參數(shù)),若單個(gè)子數(shù)組極大(如長度 > 10?),可改用 push.apply 或分批處理:
for (const subArr of arr) {
Array.prototype.push.apply(merged, subArr);
}
但 push.apply 在極端情況下也可能棧溢出,最穩(wěn)妥的方式是使用普通 for 循環(huán)逐個(gè) push。
適用場景
- 高性能要求(如數(shù)據(jù)處理、游戲引擎、實(shí)時(shí)計(jì)算)。
- 處理大型或不確定規(guī)模的嵌套數(shù)組。
綜合對比表
| 方法 | 語法簡潔性 | 執(zhí)行性能 | 內(nèi)存效率 | 兼容性 | 適用嵌套深度 | 是否修改原數(shù)組 |
|---|---|---|---|---|---|---|
| arr.flat() | ????? | ???? | ???? | ES2019+ | 可控(默認(rèn)1層) | 否 |
| [].concat(...arr) | ????? | ??? | ?? | ES6+ | 僅1層 | 否 |
| reduce() + concat | ??? | ? | ? | 廣泛(ES5+) | 僅1層 | 否 |
| for...of + push(...) | ?? | ????? | ????? | ES6+ | 僅1層 | 否 |
注:? 越多表示越優(yōu)。
最佳實(shí)踐建議
現(xiàn)代項(xiàng)目(支持 ES2019+):優(yōu)先使用 arr.flat() —— 簡潔、安全、高效。
需要兼容舊環(huán)境(如 IE11):使用 reduce 或手動 for 循環(huán),并搭配 Babel 轉(zhuǎn)譯。
處理超大數(shù)組(> 10? 元素):選擇 for...of + push,并注意單個(gè)子數(shù)組長度限制。
需要在扁平化時(shí)附加邏輯(如去重、過濾):使用 reduce,靈活組合業(yè)務(wù)邏輯。
延伸思考:完全扁平化任意深度嵌套
若面對如下結(jié)構(gòu):
const deeplyNested = [1, [2, [3, [4, [5]]]]];
可封裝遞歸函數(shù)或使用 flat(Infinity):
const flatten = arr => arr.flat(Infinity); // 或 const flatten = arr => arr.reduce( (acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val), [] );
提示:flat(Infinity) 在大多數(shù)現(xiàn)代引擎中已高度優(yōu)化,通常優(yōu)于手寫遞歸。
結(jié)語
數(shù)組扁平化雖是一個(gè)“小問題”,卻能反映出開發(fā)者對語言特性、性能邊界和工程實(shí)踐的理解深度。在實(shí)際項(xiàng)目中,應(yīng)根據(jù)運(yùn)行環(huán)境、數(shù)據(jù)規(guī)模、維護(hù)成本綜合選擇方案。對于絕大多數(shù)現(xiàn)代前端或 Node.js 應(yīng)用,arr.flat() 已足夠優(yōu)雅且高效——簡單,才是終極的復(fù)雜。
到此這篇關(guān)于JavaScript進(jìn)行數(shù)組扁平化的四種方法詳解與最佳實(shí)踐的文章就介紹到這了,更多相關(guān)JavaScript數(shù)組扁平化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript 拷貝節(jié)點(diǎn)cloneNode()使用介紹
這篇文章主要介紹了javascript 節(jié)點(diǎn)操作拷貝節(jié)點(diǎn)cloneNode()的使用,需要的朋友可以參考下2014-04-04
JS函數(shù)內(nèi)部屬性之a(chǎn)rguments和this實(shí)例解析
在函數(shù)內(nèi)部,有兩個(gè)特殊的對象:arguments和this。這篇文章主要介紹了函數(shù)內(nèi)部屬性之a(chǎn)rguments和this ,需要的朋友可以參考下2018-10-10

