- 原文地址:medium.freecodecamp.org/what-is-a-p…
- 原文做者:Yazeed Bzadough
- Markdown 地址:github.com/wanghaiqion…
純函數是程序函數式編程語言中原子構建塊(最簡單的可重用代碼構建塊)。簡單和易測試性的特色使其備受推崇。javascript
本文將提供一個快速檢測列表,用於判斷一個函數是否爲純函數。java
一個函數必須知足以下兩點才能被稱之爲「純的」:git
讓咱們逐一展開。github
比較以下兩版代碼:編程
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,尤爲是在某些特定條件下?
哪一種方式更能勝任多線程系統環境,尤爲是這種系統環境會受時序因素影響?
顯然是第一種。
這一檢測點自己也是一個檢測列表。以下是一些反作用:
基本上函數中執行的任何操做都與最終計算輸入結果無關,僅僅依賴於傳入的參數。
推薦你們看看 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
});
複製代碼
直接更改函數的輸入是有些風險的,但改變輸入的副本就沒什麼問題了。無論在哪裏調用,咱們都將獲得一個穩定可測試的函數。