JavaScript 陣列方法深度解析:forEach、map 與 reduce

作者: Calpa Liu
字數:1589
出版:2025 年 4 月 12 日
JavaScript 作為一門功能強大的程式語言,提供了多種操作陣列的高階函數方法,其中 forEach、map 和 reduce 是最常用且最具表達力的三種方法。這些方法為開發者提供了簡潔、可讀性高的寫法,能夠以宣告式而非命令式的方式處理陣列資料。本文將深入探討這三種方法的原理、使用方式、差異及適用場景,幫助開發者在實際專案中更有效地選擇和使用它們。

基本概念與原理

這三種陣列方法都是迭代陣列元素並執行指定函數的工具,但它們各自有不同的用途和行為模式。在了解它們的具體用法前,我們需要明白它們的共同點:它們都在內部使用迴圈來遍歷陣列元素,讓開發者能夠以更抽象的方式處理陣列操作。

forEach:執行副作用的迭代器

forEach 方法是最基本的陣列迭代方法,它對陣列中的每個元素執行一次提供的函數,但不返回任何值(即返回 undefined)。

array.forEach(function(currentValue, index, array) {
  // 對每個元素執行的程式碼
});

此方法的主要特點是:

  • 不返回新陣列,而是可能修改原陣列或產生副作用
  • 無法中斷迴圈(除非拋出異常)
  • 返回 undefined,因此不能鏈式調用其他陣列方法

map:轉換陣列的工具

map 方法建立一個新陣列,其中包含對原陣列中每個元素調用提供函數後的結果:

const newArray = array.map(function(currentValue, index, array) {
  // 返回轉換後的元素
  return transformedValue;
});

map 方法的關鍵特性:

  • 返回一個新陣列,長度與原陣列相同
  • 不修改原陣列(除非在回調函數中明確操作原陣列)
  • 非常適合將資料從一種形式轉換為另一種形式

reduce:聚合陣列的多功能工具

reduce 方法將陣列中的所有值聚合為單一值,它對每個元素執行一個 reducer 函數:

const result = array.reduce(function(accumulator, currentValue, index, array) {
  // 返回更新後的累加器
  return updatedAccumulator;
}, initialValue);

reduce 方法的獨特之處:

  • 需要一個累加器(accumulator)參數
  • 可以指定初始值(initialValue)
  • 最終返回一個單一值,可以是任何類型(數字、字串、物件、陣列等)
  • 極其靈活,可以用於多種複雜的資料轉換操作

深入比較:forEach vs map vs reduce

返回值的差異

這三種方法最根本的區別在於它們的返回值:

  • forEach 返回 undefined
  • map 返回新陣列
  • reduce 返回單一聚合值

這一差異直接影響了它們的可鏈式調用能力:

const myArray = [1, 2, 3, 4, 5];

// 這會拋出錯誤,因為 forEach 返回 undefined
myArray.forEach(x => x * x).reduce((total, value) => total + value);

// 這可以正常工作,因為 map 返回一個新陣列
myArray.map(x => x * x).reduce((total, value) => total + value); // 返回 55

此例清楚地展示了為何在需要進一步處理結果時,map 比 forEach 更適合。

可變性與不可變性

從函數式程式設計的角度看,map 和 reduce 通常與不可變性(immutability)相關聯,而 forEach 則傾向於可變操作:

  • forEach 經常用於修改外部狀態或執行副作用
  • map 通常用於產生新的資料結構,不修改原始資料
  • reduce 則用於轉換/聚合資料為新的形式
const items = [{ id: 1 }, { id: 2 }];

// 使用 forEach 修改原物件(可變操作)
items.forEach(item => {
  item.userId = '#abc';
});

// 使用 map 創建新物件(不可變操作)
const newItems = items.map(item => {
  return { ...item, userId: '#abc' };
});

尤雨溪的形象比喻

Vue.js 的創建者尤雨溪提供了一個非常生動的比喻來解釋這些方法:

想像你面前站了一排人(陣列中的元素):

  • forEach 就像你依次對每個人做些什麼,可能是任何操作
  • map 就像你拿著一個盒子,讓每個人將錢包扔進去,最終得到一個裝滿錢包的新盒子
  • reduce 則像是你計算所有人錢包中的錢,最終得到一個總金額

實際使用案例與範例

forEach 適用場景

forEach 最適合當你需要執行副作用而不關心返回值的情況:

// 向後端 API 發送數據
users.forEach(user => {
  sendDataToAPI(user.id);
});

// 更新 DOM 元素
elements.forEach(element => {
  element.classList.add('active');
});

map 適用場景

map 非常適合數據轉換場景,特別是在需要保留原始數據的情況下:

// 轉換用戶資料格式
const userNames = users.map(user => {
  return {
    fullName: `${user.firstName} ${user.lastName}`,
    age: user.age
  };
});

// 在 React 中渲染列表
const listItems = products.map(product => (
  {product.name} - ${product.price}
));

通常在 React 中,我們會使用 map 來生成列表,因為它會返回一個新的陣列,這有助於保持資料的不可變性。

const listItems = products.map(product => (
  <li key={product.id}>{product.name} - ${product.price}</li>
));

reduce 適用場景

reduce 在需要將陣列聚合為單一值時非常有用:

// 計算總和
const sum = numbers.reduce((total, num) => total + num, 0);

// 構建複雜對象
const groupedByCategory = products.reduce((groups, product) => {
  const category = product.category;
  if (!groups[category]) {
    groups[category] = [];
  }
  groups[category].push(product);
  return groups;
}, {});

以上範例展示了如何使用 forEach、map 和 reduce 來處理不同的資料轉換場景。

最佳實踐與選擇指南

如何在這三種方法中做出選擇?以下是一些指導原則:

  1. 使用 forEach 當

    • 你只需要迭代執行操作,不需要返回值
    • 你需要執行副作用(如 DOM 操作、發送請求)
    • 你不需要中斷迭代過程
  2. 使用 map 當

    • 你需要從現有陣列創建一個新陣列
    • 你需要轉換每個元素
    • 你希望保持資料的不可變性
  3. 使用 reduce 當

    • 你需要將陣列聚合為單一值(如總和、平均值)
    • 你需要構建複雜的資料結構
    • 其他陣列方法組合起來會顯得過於複雜

結論

forEach、map 和 reduce 是 JavaScript 中處理陣列的強大工具,它們各自有其獨特的用途和優勢。了解它們之間的差異和適用場景,可以讓你的程式碼更加簡潔、可讀和高效。

雖然 forEach 側重於產生副作用,map 專注於轉換資料,reduce 善於聚合值,但在實際開發中,它們常常協同工作,共同解決複雜的資料處理問題。選擇正確的工具,不僅可以使程式碼更加清晰,還能更好地表達你的程式設計意圖。

在當代 JavaScript 程式設計中,熟練掌握這些高階函數是成為優秀開發者的基本要求。透過恰當地使用它們,你可以寫出更具表達力、更易維護的程式碼,同時充分發揮 JavaScript 的函數式程式設計特性。

關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。

熱門文章

最新文章

圖片管理中心
管理圖片資源
IP 查詢
快速查詢和定位 IP 地址的地理位置和相關信息
Python 運行器
無需後端、無需登入,只需打開瀏覽器即可運行 Python 代碼(由 Pyodide 提供支持)
封面圖生成器
自動創建適合各種平台的文章封面圖
原作(青山剛昌)產生器
一鍵創建原作(青山剛昌)的封面圖
日本色彩
探索和使用傳統日本色彩
部落格內容洞察儀表板
以視覺化儀表板方式追蹤文章成效、分享熱度與分類分布,協助創作者掌握內容表現。
蒙特卡羅估算 π
使用蒙特卡羅方法演示 π 值的估算過程
LLM
使用 LLM 模型進行聊天
活動圖生成器
一鍵創建活動的封面圖
Wagmi Card
一鍵創建 Wagmi 的封面圖
Facebook Quote
Facebook Quote
Music Macro Language (MML) Studio
用程式語法編寫旋律,用音符構築想像
Blurhash
一鍵創建 Blurhash
文字分類器
使用 MediaPipe TextClassifier 分類文字
前端工程師免費工具資源
前端工程師免費工具資源
後端工程師免費工具資源
後端工程師免費工具資源
全端工程師免費工具資源
全端工程師免費工具資源
Web3 工程師免費工具資源
Web3 工程師免費工具資源
紫微斗數排盤系統|結合 AI 的命盤性格與事業財務分析生成器
紫微斗數排盤工具,輸入生日與時辰,自動生成完整命盤分析提示(Prompt)。結合最專業紫微理論與 AI 助力,助你深入解析性格、事業、財務與人際課題。免費使用,適合命理師及紫微愛好者。
PixAI Prompt 組合器|快速打造可用於 AI 繪圖的語言拼圖
使用 PixAI 卻不會寫 prompt?這個工具幫你一鍵組裝角色、表情、風格語彙,輸出高品質繪圖提示語句(Prompt),可直接貼入 PixAI 使用。適合插畫師、創作者、AI 新手與 VTuber 角色開發者。