js--函數式編程中的純函數與副作用

一、純函數

純函數是這樣一種函數,即相同的輸入,永遠會得到相同的輸出,而且沒有任何可觀察的副作用。

舉例1:數組的兩個方法:slice與splice。

這兩個函數的作用並無二致——但是注意,它們各自的方式卻大不相同,但不管怎麼說作用還是一樣的。我們說 slice 符合純函數的定義是因爲對相同的輸入它保證能返回相同的輸出。而 splice 卻會嚼爛調用它的那個數組,然後再吐出來;這就會產生可觀察到的副作用,即這個數組永久地改變了。

var	xs = [1,2,3,4,5];
var	xp = [1,2,3,4,5];
//純的
xs.slice(0,3); //=>[1,2,3]
xs.slice(0,3); //=>[1,2,3]
xs.slice(0,3); //=>[1,2,3]
console.log(xs); //=>[1,2,3,4,5];

//不純的
xp.splice(0,3); //=>[1,2,3]
xp.splice(0,3); //=>[4,5]
xp.splice(0,3); //=>[]
console.log(xp); //=>[];

在函數式編程中,我們討厭這種會改變數據的笨函數。我們追求的是那種可靠的,每次都能返回同樣結果的函數,而不是像 splice這樣每次調用後都把數據弄得一團糟的函數,這不是我們想要的。

舉例2:

//不純的
var	minimum	= 21;
var	checkAge = function (age)	{
	return age >= minimum;
};

//純的
var	checkAge = function (age)	{
	var	minimum	= 21;
	return age >= minimum;
};

在不純的版本中,checkAge的結果將取決於minimum這個可變變量的值。換句話說,全局作用域下的minimum改變之後,會影響checkAge的結果。在純的版本中,minimum值被限定在函數作用域中,外部無法直接修改,所以函數結果只會和參數age有關。

二、副作用

副作用是在計算結果的過程中,系統狀態的一種變化,或者與外部世界進行的可觀察的交互。

“作用”我們可以理解爲一切除結果計算之外發生的事情。
“副作用”的關鍵部分在於“副”。就像一潭死水中的“水”本身並不是幼蟲的培養器,“死”纔是生成蟲羣的原因。同理,副作用中的“副”是滋生bug的溫牀。

概括來講,只要是跟函數外部環境發生的交互就都是副作用——這一點可能會讓你懷疑無副作用編程的可行性。函數式編程的哲學就是假定副作用是造成不正當行爲的主要原因。

這並不是說,要禁止使用一切副作用,而是說,要讓它們在可控的範圍內發生。副作用讓一個函數變得不純是有道理的:從定義上來說,純函數必須要能夠根據相同的輸入返回相同的輸出;如果函數需要跟外部事物打交道,那麼就無法保證這一點了。

參考書籍:函數式編程

發佈了44 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章