JavaScript函數式編程之深切明白純函數

更多相關內容見博客 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函數式編程之副作用》

參考資料:

    原文作者:磚用西瓜
    原文地址: https://segmentfault.com/a/1190000015227477
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞