1. 程式人生 > >純函式以及為什麼要用純函式

純函式以及為什麼要用純函式

什麼函式是純的?

純函式的定義是:

1.   如果函式的呼叫引數相同,則永遠返回相同的結果。它不依賴於程式執行期間函式外部任何狀態或資料的變化,必須只依賴於其輸入引數。

2.   該函式不會產生任何可觀察的副作用,例如網路請求,輸入和輸出裝置或資料突變(mutation)。

這就是純的函式。 如果一個函式符合上述 2 個要求,它就是純函式。 你可能在過去甚至無意地情況下編寫過純函式。

在我們研究一個函式一個純或不純之前,讓我們先討論一下可怕的“副作用”。

 

什麼是可觀察的副作用?

一個可以被觀察的副作用是在函式內部與其外部的任意互動。這可能是在函式內修改外部的變數,或者在函式裡呼叫另外一個函式等。

注: 如果純函式呼叫純函式,則不產生副作用依舊是純函式。

副作用來自,但不限於:

•    進行一個 HTTP 請求

•    Mutating data

•    輸出資料到螢幕或者控制檯

•    DOM 查詢/操作

•    Math.random()

•    獲取的當前時間

副作用本身並不是毒藥,某些時候往往是必需的。 但是,對於要保持純粹的函式,它不能包含任何副作用。當然,並非所有函式都需要是純函式。 我將在稍後討論這個情況。

不過首先,讓我們來看一些純的和不純的函式對比的例子......

 

純函式的例子

以下是一個計算產品稅後價格(英國稅率是20%)的純函式的例子:

function priceAfterTax(productPrice) { return (productPrice * 0.20) + productPrice;}

 

它符合我們所說的兩條純函式的定義。不依賴於任何外部輸入,不改變任何外部資料、沒有副作用。

即使你用同樣的輸入執行執行這個函式 100,000,000 次它依舊產生同樣的結果。

 

非純函式

我們已經看了純函式的例子,現在一起來看一個非純函式(Impure function)的 JavaScript 例子:

var tax = 20;

function calculateTax(productPrice) {

    return (productPrice * (tax/100)) + productPrice;

}

暫停片刻,看看你是否能看出為什麼這個函式不純。

其中函式的計算結果取決於外部 tax 變數,而純函式不能依賴外部變數。它沒有滿足定義中的第一個要求,因此這個函式是不純的。

 

為什麼說純函式在 JavaScript 很重要?

純函式在函數語言程式設計中被大量使用。而且諸如 ReactJS 和 Redux 等優質的庫都需要使用純函式。

不過,純函式也可以用在平常的 JavaScript 開發中使用,不一定要限死在某個程式設計範例中。 你可以混合純的和不純的函式,這完全沒問題。

並非所有函式都需要是純的。 例如,操作 DOM 的按鈕按下的事件處理程式就不適合純函式。 不過,這種事件處理函式可以呼叫其他純函式來處理,以此減少專案中不純函式的數量。

 

可測試性和重構

另一個使用純函式的原因是測試以及重構。

使用純函式的一個主要好處是它們可以直接測。 如果傳入相同的引數,它們將始終產生相同的結果。

同時純函式還使得維護和重構程式碼變得更加容易。你可以放心地重構一個純函式,不必操心沒注意到的副作用搞亂了整個應用而導致終除錯地獄。(譯註:如果專案中充斥著副作用,那麼函式/模組之間的邏輯可能互相交織耦合,在後期新增邏輯時可能由於依賴複雜而難以重構,更常見的是開發為了應付需求而不斷的引入新的副作用到原本的邏輯上從而導致程式碼變得越來越糟糕。)

正確地使用純函式可以產生更加高質量的程式碼。並且也是一種更加乾淨的編碼方式。

&n