Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

JavaScript 陣列扁平化的幾種寫法

把多層巢狀陣列變成一維陣列是常見需求。記錄幾種實現方式,並對比適用場景。

場景

javascript
const nested = [1, [2, 3], [4, [5, 6]], [7, [8, [9]]]];
// 目標:[1, 2, 3, 4, 5, 6, 7, 8, 9]

方法一:遞迴

javascript
function flatten(arr) {
  return arr.reduce((flat, item) => {
    return flat.concat(Array.isArray(item) ? flatten(item) : item);
  }, []);
}

flatten([1, [2, [3, [4]]]]); // [1, 2, 3, 4]

方法二:展開運算子迴圈

javascript
function flatten(arr) {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
}

每次迴圈展開一層,直到沒有巢狀為止。

方法三:toString(限整數)

javascript
[1, [2, [3, [4]]]].toString().split(",").map(Number);
// [1, 2, 3, 4]

只適合純整數陣列,有侷限性。

方法四:Array.flat(ES2019)

javascript
// 展開一層
[1, [2, [3]]]
  .flat() // [1, 2, [3]]

  [
    // 展開兩層
    (1, [2, [3, [4]]])
  ].flat(2) // [1, 2, 3, [4]]

  [
    // 無限層展開
    (1, [2, [3, [4]]])
  ].flat(Infinity); // [1, 2, 3, 4]

最簡潔,2018 年底 Chrome 69+ 支援,需要 polyfill。

指定深度展開

javascript
function flattenDepth(arr, depth = 1) {
  if (depth === 0) return arr.slice();
  return arr.reduce((flat, item) => {
    if (Array.isArray(item) && depth > 0) {
      return flat.concat(flattenDepth(item, depth - 1));
    }
    return flat.concat(item);
  }, []);
}

flattenDepth([1, [2, [3, [4]]]], 2); // [1, 2, 3, [4]]

實際專案場景

javascript
// 場景:樹形選單資料,獲取所有葉子節點
const menuTree = [
  { id: 1, name: "首頁" },
  {
    id: 2,
    name: "使用者管理",
    children: [
      { id: 3, name: "使用者列表" },
      { id: 4, name: "角色管理" },
    ],
  },
];

// 獲取所有選單項(包括父級)
function flattenMenu(menus) {
  return menus.reduce((flat, menu) => {
    if (menu.children) {
      return flat.concat(menu, flattenMenu(menu.children));
    }
    return flat.concat(menu);
  }, []);
}

flattenMenu(menuTree);
// [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]

效能對比

對於大陣列,遞迴方式最快;Array.flat 內部也是最佳化的;toString 方式建立字串成本高。

小結

  • 日常開發:flat(Infinity) 最簡潔(確認目標環境支援)
  • 需要相容舊瀏覽器:遞迴 reduce 方式
  • 只有整數:toString().split(',').map(Number) 也行
  • 樹形資料到平鋪列表:用遞迴,處理 children

MIT Licensed