更多相關內容見博客 https://github.com/zhuanyongxigua/blog
純函數是函數式編程的基礎,須要重點明白。
純函數的觀點:
純函數是如許一種函數,即雷同的輸入,永久會獲得雷同的輸出,而且沒有任何可視察的副作用。
他的重點在於“雷同的輸入,永久會獲得雷同的輸出”,背面所說的副作用也是為了滿足這一點。
在細緻申明純函數之前,先講兩個其他的觀點:可變數據類型和不可變數據類型。
我們曉得,在JavaScript中,基礎數據類型都是不可變的,他們只能被替代,不能被修正。比方當我們在對字符串舉行操縱的時刻,我們並不能轉變這個字符串自身。
var str = 'I am hero';
console.log(str.toUpperCase()); // "I AM HERO"
console.log(str); //"I am hero"
我們能做的只需把返回的新字符串從新賦值給變量。
var str = 'I am hero';
str = str.toUpperCase(); // "I AM HERO"
而援用數據類型都是可變的,存在變量中的僅僅就是一個地點。關於可變特徵,facebook的immutable.js做了針對性的強化處置懲罰,另外另有clojurescript如許越發完整的體式格局。
為何我要說這兩個觀點呢?
先不說在JS運轉的體系環境中可能會發生副作用,單單看這些可變的數據類型,就會增添我們寫純函數的難度,要十分注重,個別狀況我們只能挑選接收。
如許的話想,在JS中,我們無妨把純函數換一種體式格局明白,不要把它當作一個只需“完整滿足請求”和“不滿足請求”的規範,而要把它設想成一個局限,在這裡有上下差別水平的純函數。
怎樣明白“雷同的輸入,永久會獲得雷同的輸出”
文章開首的純函數的觀點中的“永久”可能會讓你迷惑,要把它放在詞法作用域中斟酌,也就是說不斟酌再下次實行之前修正常量這一類的狀況。
例一
var a = 5;
function A(b) {
return a + b;
}
A(5);
A函數是一個純函數嗎?明顯異常不純,在順序實行的過程當中,變量a很輕易被修正,這就會致使每次挪用A(5)
的返回值轉變。
例二
對例一稍作修正
const a = 5;
function A(b) {
return a + b;
}
A(5);
這是純函數,肯定的輸入,肯定的輸出。
例三
把例二数字常量換成對象
const obj = {id: 5};
function A(_obj) {
return _obj.id;
}
A(obj);
函數A基礎上是純函數,為何說是“基礎上”?因為有極度狀況以下
var obj = {
get id() {
return Math.random();
}
}
注重,obj在傳進函數A之前是肯定的,getter
是在取值的時刻才會實行,然則返回的結果是不肯定的,所以這個時刻函數A就不是純函數了。隨機數和Date
都邑形成函數不純,運用的時刻要注重。
除此之外,因為對象是可變數據類型,我們在每次輸入變量obj
到函數A中時,並不具有相對的自信會返回肯定的值。可關於函數A來講,它只關心傳進來的數據是什麼,而關於誰人數據來講,只需不是上面的極度狀況,返回的是肯定的值。
例四
const obj = {a: 5};
function A(b) {
return obj.a + b;
}
A(5);
這個很明顯很不純,同例一,注重與例三的區分。
例五
對例四稍作修正
const obj = Object.freeze({a: 5});
function A(b) {
return obj.a + b;
}
A(5);
如許就純多了,但是須要注重的是,Object.freeze()
這個要領沒法凝結嵌套的對象,比方
const obj = Object.freeze({a: {a: 5}});
obj.a.a = 10;
function A(b) {
return obj.a.a + b;
}
console.log(A(5)); // 15,不純
例六
function foo(x) {
return bar(x);
}
function bar(y) {
return y + 1;
}
foo(1);
都純。
例七
function A(a) {
return function(b) {
return a + b;
}
}
var B = A(5);
函數A和函數B是純函數嗎?起首來看函數A,每次輸入一個參數,都邑獲得一個用這個參數構成的函數,獲得的函數是牢固的,所以函數A是純函數;再來看函數B雖然看起來彷佛運用了一個本身外部的變量a,而且這個變量a可能會常常轉變,但是,函數B肯定要在挪用了函數A以後才獲得,而且獲得了以後,變量a是沒法轉變的,這就很純了。
即便在返回函數B之前修正了a,比方
例八
function A(a) {
a = 0;
return function(b) {
return a + b;
}
}
var B = A(5);
結論也是一樣的。
可假如如許寫
例九
function A(a) {
return function(b) {
return a = a + b;
}
}
var B = A(5);
關於副作用,見《JavaScript函數式編程之副作用》
參考資料: