我的以爲這個定義肥腸生動形象了。
函數式編程到處體現着數學的邏輯思想,經過減小外部依賴來避免外部變量的改變對於程式內部狀態的改變,使得程序變得簡易、聲明式、易於維護。
這裏推薦一下F大的《JS函數式編程指南》,系統介紹了函數式編程的思想。
中文版電子書下載地址走你:https://llh911001.gitbooks.io...
本文章是本身閱讀後的一些理解和記錄~html
這個概念一樣出於書中。規定了變量能夠取的值得範圍,以及該類型的值能夠進行的操做。根據類型的值的可賦值情況,能夠把類型分爲三類。git
在scala中,函數是能夠做爲參數來傳遞而且返回的,因此scala中的函數就是first class function
PS:scala 是一門多範式(multi-paradigm)的編程語言,設計初衷是要集成面向對象編程和函數式編程的各類特性。
所以,function做爲變量的一種,能夠被儲存,看成參數傳遞,或者被複制給變量等等...程序員
首先弄清純函數的概念:Pure function
意指相同的輸入,永遠會獲得相同的輸出,並且沒有任何顯著的反作用。
它符合兩個條件:編程
簡單來講,也就是當一個函數的輸出不受外部環境影響,同時也不影響外部環境時,該函數就是純函數,也就是它只關注邏輯運算和數學運算,同一個輸入總獲得同一個輸出。
好比slice
和splice
,可是slice
是純函數,而splice
不是,由於後者會改變源數據。
這就是強調使用純函數的緣由,由於純函數相對於非純函數來講,在可緩存性、可移植性、可測試性以及並行計算方面都有着巨大的優點。數組
看一下書中的例子:緩存
// impure var minimum = 21; var checkAge = function(age) { return age >= minimum; }; // pure var checkAge = function(age) { var minimum = 21; return age >= minimum; };
在impure 的版本中,checkAge 的結果將取決於 minimum 這個變量,換句話說,除了輸入之外,它將取決於系統狀態,一旦引用了外部環境,它就不符合pure了。
固然,也能夠直接凍結變量,使得狀態再也不變化,那麼它也是一個純函數:less
var immutableState = Object.freeze({ minimum: 21, });
書中定義柯里化的概念是:你能夠只透過部分的參數呼叫一個 function,它會回傳一個 function 去處理剩下的參數。
函數柯里化是一種「預加載」函數的能力,經過傳遞一到兩個參數調用函數,就能獲得一個記住了這些參數的新函數。從某種意義上來說,這是一種對參數的緩存,是一種很是高效的編寫函數的方法,將一個低階函數轉換爲高階函數的過程就叫柯里化。編程語言
//舉個栗子 var checkage = min => (age => age > min); var checkage18 = checkage(18); checkage18(20); // =>true var curry = require('lodash').curry; //柯里化兩個純函數 var match = curry((what, str) => str.match(what)); var filter = curry((f, ary) => ary.filter(f)); //判斷字符串裏有沒有空格 var hasSpaces = match(/\s+/g); hasSpaces("hello world"); // [ ' ' ] hasSpaces("spaceless"); // null var findSpaces = filter(hasSpaces); findSpaces(["tori_spelling", "tori amos"]); // ["tori amos"]
假設要對某個字符串作一系列操做,咱們作的事情一多,嵌套的層數會很是深。相似於巢狀堆積(好比c(b(a())))這種堆砌方式很是不直觀,當咱們但願代碼以平行方式(書中成爲左傾)組合執行時,就成爲Compose
compose 的概念直接來自於數學課本,因此compose都有的一個特性:ide
// 結合律(associativity) var associative = compose(f, compose(g, h)) == compose(compose(f, g), h); // true
pointfree 模式指的是,永遠沒必要說出你的數據。它的意思是說,函數無須說起將要操做的數據是什麼樣的函數式編程
// 非 pointfree,因為我們提到資料:word var snakeCase = function(word) { return word.toLowerCase().replace(/\s+/ig, '_'); }; // pointfree var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);
這種風格可以幫助咱們減小沒必要要的命名,讓代碼保持簡潔和通用。
固然,爲了在一些函數中寫出Point Free的風格,在代碼的其它地方必然是不那麼Point Free的,這個地方須要本身取捨。
// 命令式 var makes = []; for (var i = 0; i < cars.length; i++) { makes.push(cars[i].make); } // 宣告式 var makes = cars.map(function(car) { return car.make; });
命令式代碼:命令「機器」如何去作事情(how),這樣無論你想要的是什麼(what),它都會按照你的命令實現。
聲明式代碼:告訴「機器」你想要的是什麼(what),讓機器想出如何去作(how)。
命令式的循環要求你必須先實例化一個數組,並且執行完這個實例化語句以後,解釋器才繼續執行後面的代碼。而後再直接迭代 cars 列表,手動增長計數器,就像你開了一輛零部件所有暴露在外的汽車同樣。這不是優雅的程序員應該作的。
聲明式的寫法是一個表達式,如何進行計數器迭代,返回的數組如何收集,這些細節都隱藏了起來。它指明的是作什麼,而不是怎麼作。除了更加清晰和簡潔以外,map 函數還能夠進一步獨立優化,甚至用解釋器內置的速度極快的 map 函數,這麼一來咱們主要的業務代碼就無須改動了