js函數式編程(1)-純函數
我將寫的第一個主題是js的函數式編程,這一系列都是mostly adequate guide這本書的讀書總結。原書在gitbook上,有中文版。由於原作者性格活潑,書中夾雜很多俚語,並且行文灑脫。中文譯版難免有時需要思量一番,既然讀了就寫出來,能方便別人最好,也請讀者指正。正文如下。
如果一個函數是純函數,那麽其不依賴外部環境,並且不產生副作用。
- 1.不依賴外部環境,反例如下:
const a1 = 10;
const aFunc1 = () => {
// 依賴外部變量
return a1;
}
依賴外部環境的函數在運行時必須滿足環境條件,如上,aFunc1在a1創建之前運行,就出錯了。
2.不產生副作用。所謂副作用,是一切與外部交互的作用,比如console.log,IO,網絡請求等。這些操作的結果是不可預計的,所以當包含副作用操作的函數執行後,結果是不可預計的。比如IO讀寫失敗,網絡出現問題,console.log通常沒什麽問題,但這仍然是外部的。舉個片面的例子,在react裏使用,就有可能因為打印某個在未來會被改變的狀態,導致組件不必要的被刷新。
3.函數與外部的合法交互只能通過參數傳遞的方式。
那麽為什麽要用純函數,純函數和函數式編程有什麽關系?
函數式編程,本質上是數學,它是數學現有理論在編程上的實現,在數學上,一個定理成立通常要滿足一些數學條件,函數式編程也需要滿足條件,這個條件就是函數必須是純函數。
那麽這是什麽數學理論呢?
如上圖,可以用一個函數表達式描述,即y = f(x),這是一種一一對應關系,輸入x能得到唯一的結果y。也就是說x經過f的轉換變成y,這個過程是穩定的,確定的,以此類推,y也可以經過某種確定的轉換g,變成z,那麽就具有如下等式:
\[y = f(x) = 2x\]
\[z = g(y) = y + 1\]
\[z = g(f(x)) = w(x) = 2x + 1\]
也就是說x經過w轉換,可以變成z
某個狀態經過多個函數轉換成另一個狀態,那麽中間轉換過程可以結合成一個轉換,這大大的使問題簡化,這是函數式編程帶來的好處,而且只是一部分的好處,而這都基於純函數。
如何看待副作用?
當然,我們知道,很多時候無法避免使用副作用。就如發送消息,必須經過網絡。那是否函數式編程沒有實際運用價值呢?當然不是。所有事情都不應該極端的理解,函數式編程的種種定理必須以純函數作為根基,目的是寫出健壯的,聲明式的代碼。可以利用函數式編程中如curry,functor,monad等奇巧淫記,將副作用加以限制並降到最低限度,保證代碼的大部分是純的。
js函數式編程(1)-純函數