HOWTO · JavaScript
JavaScript 中物件陣列的總和
本教程演示瞭如何在 javascript 中對一組物件求和
本頁內容
若要加總物件陣列中某個屬性的值,可以逐一走訪物件,並將該屬性加到累計總和中。舉例來說,如果每個物件都有數值型的 amount,就能用 JavaScript 的 reduce() 算出總和。若希望清楚呈現每次迭代,也可以用 forEach 或 for...of 迴圈完成相同計算。
以下範例使用相同的三筆記錄,方便比較不同寫法;它們的 amount 值總和為 600。
使用 reduce() 加總物件屬性
reduce() 會針對陣列中的每個元素呼叫回呼函式,並將回呼函式傳回的值帶到下一次呼叫,作為累加器。以下範例中,回呼函式的第一個參數是目前的累計總和,第二個參數則是目前的物件。最後的 0 是累加器的初始值,因此即使陣列沒有任何記錄,計算也有明確的起始值。
執行此範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
const items = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
{ id: 3, amount: 300 },
];
const total = items.reduce((sum, item) => sum + item.amount, 0);
console.log(total);
這段程式會加總大小寫有別的 amount 屬性,並輸出計算結果。屬性名稱的拼寫和大小寫必須完全相同:item.Amount 指的是另一個不同的屬性。當轉換過程清楚地產生單一累計結果時,適合使用 reduce()。如果要加總的值是從每個物件計算而來,可以在回呼函式中計算;也可以另外使用 map() 投影出所需的值,但 map() 會轉換每個元素,不會篩選記錄。
使用 forEach() 加總物件屬性
forEach 會走訪陣列中的每個項目並執行回呼函式,但不會傳回累計總和。請先在回呼函式外初始化一個獨立變數,再將每個項目的屬性值加到該變數中。如果更新總和時需要執行多個陳述式,這種寫法可能更容易閱讀。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
const items = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
{ id: 3, amount: 300 },
];
let total = 0;
items.forEach((item) => {
total += item.amount;
});
console.log(total);
由於回呼函式會更新累加器,因此必須用 let 宣告它。請將總和變數限制在這項計算所需的範圍內,也不要預期 forEach 的傳回值會包含總和。如果明確的回呼函式和具名的累計變數能讓團隊更容易理解程式碼,就可以選擇這種寫法。
使用 for...of 迴圈加總物件屬性
for...of 迴圈也會走訪可迭代陣列中的每個項目。它提供直接的迴圈主體,適合需要略過某些記錄、檢查多個屬性,或在計算中加入其他控制流程的情況。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
const items = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
{ id: 3, amount: 300 },
];
let total = 0;
for (const item of items) {
total += item.amount;
}
console.log(total);
若只是計算簡單的總和,這三種模式都能表達相同的加法。請選擇能讓周邊邏輯最容易理解的寫法;目前沒有基準測試資料能支持任何一種方法普遍較快的說法。以下範例都假設 amount 是數字。若加上字串,字串可能會與累計總和串接;若加上 undefined,結果則會是 NaN。因此,請先決定如何驗證或正規化輸入資料。
處理缺少的值與條件式加總
如果某個屬性可能不存在或是 null,請先決定該筆記錄應視為不貢獻總和,還是應拒絕這筆資料。如果預期的處理方式是將兩者都視為零,可以使用空值合併運算子。它會保留有效的數值 0,不會像真值判斷的替代寫法一樣把零當成不存在。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
const items = [
{ id: 1, amount: 100 },
{ id: 2 },
{ id: 3, amount: null },
];
const total = items.reduce((sum, item) => sum + (item.amount ?? 0), 0);
console.log(total);
空值合併運算子會處理 null 和 undefined,但不會讓任意字串自動成為有效數字。處理外部資料時,請先驗證再加總。例如,檢查 typeof item.amount === "number",然後依應用程式需求略過非數值,或回報這些值。除非輸入格式明確定義轉換方式,否則不要默默轉換值。
若只想納入符合條件的物件,可以在累加回呼函式或迴圈中加入條件。這樣就不會把 map() 誤當成篩選方法。以下範例只會加總 paid 旗標值為 true 的記錄金額:
const items = [
{ amount: 100, paid: true },
{ amount: 200, paid: false },
{ amount: 300, paid: true },
];
const paidTotal = items.reduce(
(sum, item) => sum + (item.paid ? item.amount : 0),
0
);
console.log(paidTotal);
若要在同一輪走訪中加總多個屬性,可以將物件用作 reduce() 的累加器,例如 { amount: 0, tax: 0 },並在每筆資料處理後傳回更新過的物件。若只需加總單一屬性,使用數值累加器會更簡單。實際選擇 reduce()、forEach 或 for...of 時,請依照計算需求,判斷哪種方式最適合:傳回累計值、使用明確的回呼函式,或直接控制迴圈。