紀錄工作經驗、相關知識,解決技術相關問題。

Javascript, React, 工作雜談, 新手 Jamp Holes, 網站相關

JS去除 array 中 null 或空值

JS去除 array 中 null 或空值 特色圖片

在前端開發與串接 API 處理後端回傳的資料時,經常會遇到原始資料夾雜著 null、undefined 或空值的情況。學會如何正確地進行 JS去除 array 中 null 或空值,能有效避免後續迭代處理時噴出非預期錯誤。想了解基礎原理細節可前往 [JS] 字串將每個字逐一拆解成陣列 與 JS 陣列加總與平均值怎麼算?Array.reduce 初始值設定與物件求和範例 建立觀念。接著我們就直接切入主題,看看如何透過 JavaScript 內建方法高效過濾陣列中的雜訊。

一、 JavaScript 一維陣列去除 null 與空值基本方法

假設你有一筆簡單的一維陣列資料,長得像這樣:

const a = [
  null,
  null,
  1,
  2,
  3,
  null,
  10
];

如果你希望將該資料中的 null 清除,可以透過 filter 搭配條件判斷來達成:

a.filter(e => e);

由於在 JavaScript 中,null、undefined、0、"" (空字串) 等值在進行條件判斷時都會被強制轉型為 false (Falsy 值)。如果你的目標是要過濾掉這些常見的空值,也可以直接簡化傳入 Boolean 建構函式,利用這個特性來達到資料過濾的目的:

a.filter(Boolean);

二、 多維陣列與複雜巢狀結構的清理策略

當資料結構再複雜一點,變成含有巢狀陣列的多維資料時,單純對一維陣列使用的 filter 就無法完全清除內層的 null。這時你可以結合 map 與條件判斷來處理:

const a = [
  null,
  null,
  [
    {a:1, b:2},
    null,null,null,null,
    5,
  ],
  [
    {a:11, b:22},
    10,
  ],
  [
    {a:111, b:222},
    123,
    456,
    null,null,
    5,
    null,null,
  ],
  null,
  10
];

a.filter(Boolean).map(e => Array.isArray(e) ? e.filter(Boolean) : e);

在寫這類邏輯時,整體的思路是先對外層做一次過濾,再透過 map 走訪每個元素,並針對子層資料再次進行過濾。


三、 處理三維以上深層巢狀陣列的遞迴解法

當巢狀結構不只兩層,而是擴展到三維甚至更深的未預期深度時,單次使用的 map 搭配 filter 就無法完全清除所有的 null 空值。面對這種動態且深層的巢狀結構,最妥善的做法是改用遞迴(Recursion)函式來逐層深入清理。

透過遞迴,函式會自我呼叫來檢查每一個元素:只要遇到陣列就繼續往內遞迴過濾,直到確認最底層的非陣列資料為止,同時一併將當前層級的 null 與 Falsy 值透過 filter(Boolean) 排除。

const deepRemoveNull = (data) => {
  // 如果不是陣列,直接回傳原值
  if (!Array.isArray(data)) {
    return data;
  }

  // 先過濾掉當前層級的空值,並對每個元素進行遞迴處理
  return data
    .filter(Boolean)
    .map(item => deepRemoveNull(item));
};

const deepData = [
  null,
  [
    1,
    null,
    [
      2,
      null,
      [3, null, 4]
    ]
  ],
  10
];

console.log(deepRemoveNull(deepData));
// 輸出結果:[ [ 1, [ 2, [ 3, 4 ] ] ] ], 10 ]

四、 實務踩坑、注意事項與封裝共用函式

在實際專案開發中處理陣列過濾時,有幾個常見的邊界條件與維護要點需要特別留意:

  1. 型態防護:在對元素執行操作前,必須先透過 Array.isArray() 判斷該資料是否為陣列,否則當遇到物件、字串或數字時呼叫過濾方法便會產生執行階段錯誤。
  2. Falsy 值誤判:使用 Boolean 篩選會一併過濾掉 0、false 與空字串 ""。如果你的業務邏輯中 0 是合法且需要保留的有效數值,請改用明確的比較判斷式(例如 e !== null && e !== undefined)來取代 filter(Boolean)。
  3. 共用函式封裝:假設你在專案中有多個地方都需要用到這項清理邏輯,建議可以將過濾動作獨立封裝成共用函式,方便後續直接呼叫:
const a = [
  null,
  null,
  [
    {a:1, b:2},
    null,null,null,null,
    5,
  ],
  [
    {a:11, b:22},
    10,
  ],
  [
    {a:111, b:222},
    123,
    456,
    null,null,
    5,
    null,null,
  ],
  null,
  10
];

const removeNull = (data) => {
  return Array.isArray(data) ? data.filter(Boolean) : data;
};

removeNull(a).map(e => removeNull(e));

五、 常見問題 (Q&A)

Q1:使用 filter(Boolean) 會不小心把數字 0 或空字串 "" 濾掉嗎?該怎麼辦?

解答:會的。Boolean 建構函式在 JavaScript 中會將所有 Falsy 值(包含 null、undefined、0、""、false、NaN)一併視為無效值並過濾掉。如果你的業務邏輯中,0 或空字串是合法的有效數值,請避免直接使用 filter(Boolean),改用明確的條件判斷式(例如:e => e !== null && e !== undefined)來精準過濾 null 與 undefined。

Q2:如果陣列內夾雜物件(Object),直接用 filter(Boolean) 會把物件刪掉嗎?

解答:不會。在 JavaScript 中,任何非空物件與陣列(包含 {}、[])在進行布林轉型時皆為 truthy。因此,當陣列中夾雜物件時,filter(Boolean) 會保留這些物件,只會剔除真正的 null 或 undefined。若需同時過濾物件內部的空值屬性,則需要額外撰寫遞迴函式或屬性檢查邏輯。

Q3:後端 API 回傳的資料結構不固定,有時候是 null 而不是陣列,該怎麼預防前端直接當機?

解答:在對後端回傳的資料呼叫 .filter() 或其他陣列方法前,務必先進行防禦性檢查。最常見的做法是利用預設參數或邏輯運算子確保其型態為陣列,例如寫成 (response.data || []).filter(Boolean),或者透過前文提到的 Array.isArray() 函式先行攔截,避免因型態錯誤導致畫面直接白屏噴錯。

參考資料與延伸閱讀

發佈留言