Section 1:FP 不是什麼神祕的東西
「函數式程式設計(Functional Programming,FP)」聽起來很學術,但它的核心哲學其實非常直白:「用函數的組合來描述程式要做什麼,而不是一步步告訴電腦怎麼做」。
你不需要去讀 Haskell 或 Erlang 才能理解 FP。JavaScript 本身就是一門多範式語言, 你早就在不知不覺中使用 FP 的概念了——.map()、.filter()、.reduce() 都是 FP 的體現。
「OOP(物件導向)把程式看成一群互相傳遞訊息的物件;FP 把程式看成一系列資料的轉換管道。 兩者都是工具,選哪個取決於你在解決什麼問題。」
命令式 vs 函數式:同一個需求,兩種思維
假設任務是:從一個數字陣列中取出偶數,並乘以 2。
函數式版本更短、更易讀,而且每一步的意圖都清晰:filter 負責篩選,map 負責轉換。 你不需要追蹤 i 這個變數的狀態。
FP 的三大核心原則
1. 純函數
相同輸入,永遠相同輸出,沒有副作用
2. 不可變性
不修改資料,而是產生新資料
3. 函數組合
用小函數組合成大函數
這三個原則環環相扣:因為函數是純的,你才能放心組合它們;因為資料是不可變的, 你才能確保組合後的行為是可預測的。接下來我們一個一個深入拆解。
Section 2:純函數 — FP 的基礎
純函數(Pure Function)的定義只有兩條規則:
- 相同輸入,永遠回傳相同輸出(Deterministic)
- 沒有副作用:不修改外部變數、不發 API、不寫 log、不修改 DOM
Memoize 能運作的前提就是「純函數」。如果函數有副作用或依賴外部狀態, 快取的結果可能是過時的,memoize 就失去意義了。這是純函數帶來的直接好處。
React Component 就是純函數!
React 的設計哲學本身就建立在純函數之上。一個理想的 React component 就是:props → JSX,相同的 props 永遠渲染出相同的結果。
重點:副作用不是壞事,程式本來就需要副作用(否則什麼都做不了)。 FP 的原則不是「消滅」副作用,而是把副作用「推到系統邊界」,讓核心邏輯保持純函數、可測試。 React 中,副作用被集中在 useEffect 中處理,就是這個原則的體現。
Section 3:不可變性(Immutability)
為什麼要不可變?想像你有一個 user 物件, 同時被 10 個函數使用。如果其中一個函數偷偷修改了它,其他 9 個函數的行為就可能變得不可預測—— 這就是 共享可變狀態(Shared Mutable State)帶來的噩夢。
Immer — 讓不可變更直觀
深層不可變更新的程式碼(多層 spread)寫起來很冗長、容易出錯。Immer 讓你用「看起來像在直接修改」的語法,底層卻保證完全不可變。 Redux Toolkit 內部也是用 Immer 的。
為什麼 React 的 setState 要用不可變的方式更新? 因為 React 用Object.is()(淺比較)來判斷狀態是否改變。 如果你直接修改物件(mutation),React 看到的是同一個參考,會認為狀態沒有改變,不觸發重新渲染。 這是 React 最常見的 bug 來源之一。
Section 4:高階函數 — 函數當參數
高階函數(Higher-Order Function,HOF):接受函數作為參數, 或回傳一個函數的函數。這是 FP 最重要的特性,讓函數可以被組合和複用。
Section 5:函數組合(Function Composition)
函數組合是 FP 的精髓:把多個小函數串接成一個大函數。 就像數學中的 f(g(x)),每個函數的輸出是下一個函數的輸入。
compose vs pipe 的差異:compose 從右到左執行(數學慣例:f∘g∘h = f(g(h(x)))),pipe 從左到右執行(符合人類閱讀順序)。 實際工作中 pipe 更常用,因為執行順序和程式碼書寫順序一致。
Section 6:Maybe Monad — 優雅處理 null/undefined
Monad 是 FP 中最讓人望而生畏的概念,但它的核心思想其實很簡單:「把一個值包進容器,讓你可以鏈式地對它做操作,而不用每一步都手動處理邊界情況」。
最實用的 Monad 是 Maybe,專門用來優雅地處理可能為 null 或 undefined 的值, 避免一層一層的 null check。
實務建議:在現代 JavaScript 中,Optional Chaining(?.) 已經解決了大部分 Maybe Monad 的使用場景。學習 Maybe/Either 的主要價值在於 理解「把副作用和錯誤包進容器、讓程式碼保持可組合」的思想, 這個概念在 RxJS 的 Observable、Promise 的鏈式呼叫中都有體現。
Section 7:FP 在 React 生態系的實際應用
FP 不是紙上談兵的學術概念。React 的整個設計哲學就建立在函數式程式設計之上: Components 是純函數、Hooks 是高階函數、State 更新必須不可變。 讓我們看看幾個真實場景。
a. 資料轉換管道
b. useReducer 就是純函數
c. 自定義 Hook 的函數組合
總結:FP 不需要你放棄 OOP,也不需要你完全重寫現有的程式碼。 它更像是一種思維方式:優先使用純函數、避免共享可變狀態、用小函數組合成大函數。 從今天起,當你寫 .map().filter().reduce()、 用 Immer 更新 state、寫 useReducer 的 reducer 時,你都已經在實踐 FP 了。