- 原文地址:medium.freecodecamp.org/what-is-a-p…
- 原文作者:Yazeed Bzadough
- Markdown 地址:github.com/wanghaiqion…
純函式是程式函數語言程式設計語言中原子構建塊(最簡單的可重用程式碼構建塊)。簡單和易測試性的特點使其備受推崇。
本文將提供一個快速檢測列表,用於判斷一個函式是否為純函式。
檢測列表
一個函式必須滿足如下兩點才能被稱之為“純的”:
- 相同的輸入 總是 返回相同的輸出
- 不產生副作用
讓我們逐一展開。
1、相同的輸入 => 相同的輸出
比較如下兩版程式碼:
const add = (x, y) => x + y;
add(2, 4); // 6
複製程式碼
let x = 2;
const add = (y) => {
x += y;
};
add(4); // x === 6 (the first time)
複製程式碼
純函式 = 穩定的結果
不管你在何時何地呼叫第一個例子中的函式,得到的結果僅僅依賴於傳入的引數。
如傳入 2
和 4
,得到結果 6
。
輸出不受其他任何因素影響。
非純函式 = 不穩定的結果
第二個例子中的函式什麼也不返回。它的工作依賴於 共享狀態,遞增了一個外部變數。
這樣的話就是開發者的噩夢了。
共享狀態 具有時序依賴性。在不同的時機呼叫,會得到不一樣的結果。第一次得到的結果是 6
,第二次是 10
以此類推。
哪一版更加合理?
哪種方式更不容易產生 bug,尤其是在某些特定條件下?
哪種方式更能勝任多執行緒系統環境,尤其是這種系統環境會受時序因素影響?
顯然是第一種。
2、不產生副作用
這一檢測點本身也是一個檢測列表。如下是一些副作用:
- 更改輸入
- console.log
- HTTP 請求(AJAX、fetch)
- 更改檔案系統
- DOM 查詢
基本上函式中執行的任何操作都與最終計算輸入結果無關,僅僅依賴於傳入的引數。
推薦大家看看 Uncle Bob Martin 對於系統狀態問題的講解視訊。大約從 15min 處開始。
如下是產生了副作用的不純函式。
還湊合
const impureDouble = (x) => {
console.log('doubling', x);
return x * 2;
};
const result = impureDouble(4);
console.log({ result });
複製程式碼
雖說 console.log
產生了副作用,但實際上它沒什麼不良影響。我們仍然能保證相同的輸入得到相同的輸出。
然而接下來這個就不一樣了,可能會導致一些問題。
“純度汙染”改變了物件
const impureAssoc = (key, value, object) => {
object[key] = value;
};
const person = {
name: 'Bobo'
};
const result = impureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
複製程式碼
函式中的賦值語句,已經讓變數 person
發生了不可逆的改變。
共享狀態意味著 impureAssoc
的影響不那麼明顯。要理解它對系統產生的副作用,需跟蹤它涉及到的每一個變數,瞭解這些變數的歷史變化軌跡。
把 impureAssoc
變純很簡單,我們只要返回一個包含所需屬性的新物件即可。
使它變純
const pureAssoc = (key, value, object) => ({
...object,
[key]: value
});
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
複製程式碼
現在 pureAssco
返回一個明確可測試的結果,不再擔心它會在其他地方偷偷地變了。
想將它變純,你甚至可以如下這麼做:
另一種變純之法
const pureAssoc = (key, value, object) => {
const newObject = { ...object };
newObject[key] = value;
return newObject;
};
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
複製程式碼
直接更改函式的輸入是有些風險的,但改變輸入的副本就沒什麼問題了。不管在哪裡呼叫,我們都將得到一個穩定可測試的函式。
總結
- 不產生副作用,並且相同的輸入總是返回相同的輸出,那麼這個函式是純函式。
- 副作用包括但不限於:更改輸入,HTTP 請求,磁碟寫入,列印。
- 可以將函式輸入拷貝一份用於更改,不要去動原來的資料。
- 擴充套件運算子語法(... 語法)是一種複製物件或者資料的簡便方法。