在編程的世界裏有兩種基本類型的編程:
函數式編程(OFP):強調將一系列的「動做」組合成一個體系;
對象式編程(OOP):強調將一系列的成分聚合到一個類中;
對於javascript這種弱類語言來講,它既有OOP的特色(經過class或者prototype封裝一個類),又有OFP的特色。而接下來主要介紹一下js的OFP。javascript
本博客主要以幾個方面介紹js的OFP:一等函數,閉包,高階函數,函數柯里化,函數的純度;前端
定義:形容函數能夠像數值同樣自由穿梭在程序的不一樣地方;
1)能夠像數值同樣保存在一個變量之中:java
const a1 = 1 const a2 = function(){...}
2)能夠像數值同樣保存在數組中:編程
let arr = [10, 12, function(){...}]
3)能夠和數值同樣成爲對象的成員:redux
const obj = { a: 1, b: function(){...} }
4)能夠像數值同樣馬上運算:數組
(function(){...})()
5)能夠做爲函數的參數前端框架
function A (){...} function B (A){...}
6)能夠做爲函數的返回值閉包
function A(){ return function(){...} }
定義:(閉包的定義有多種多樣,而這裏的定義是本人的理解)閉包其實是一個函數,該函數做用域能捕捉外部的綁定,並以值的形式做爲外部函數的返回值;外部的綁定其實都是爲了閉包的調用而定義和設置。
外部的綁定:就是外部函數定義的局部變量或者外部函數的傳參(後面會比較詳細介紹)
特色:被捕捉的外部綁定不會隨着外部函數回收而回收,而是一會被閉包所引用,一直存在。
demo:框架
1)自由變量
閉包函數中所綁定的外部函數的變量;
特色:
a)自由變量必定不會在閉包函數內定義;
b)自由變量能夠是外部函數內的聲明,也能夠是外部函數的傳參;
c)自由變量能夠是變量,也能夠是函數;dom
2)變量遮蔽:
定義:兩個變量的命名相同,則出現變量遮蔽現象(該兩個變量可能存在於同一個做用域,能夠能處於不一樣的做用域)
特色:該變量被調用時,離該變量最近的同名變量會覆蓋上面的同名變量;(簡單的說就是就近原則)
定義:函數必須是一等函數,且函數的參數中至少存在一個數參數爲函數或者該函數的返回值是一個函數。
特色:擴展性好,靈活多變;
1)函數參數的高階函數:
注意:每一個函數參數都必需要肯定它在函數中的做用和功能;
demo:
[{a:1,b:‘today’},{a:2,b:‘tomorrow’}]最大值所對應的元素;
2)閉包的高階函數
注意:經過獲取外層函數的自由變量,從而定義閉包函數的行爲和做動;
定義:將一個接受多個參數只調用一次的函數,轉變成接受一部分參數且屢次調用的函數
形式:f(a1,a2,a3,...an) 等效於fn(a1,a2)(a3,...)....(an)
特色:
每執行一個邏輯參數都會返回一個函數,知道最後一個參數調用完,參數纔會執行完。
純函數:一個函數的輸入,輸出的值都是肯定且有相同的結構,且函數內部不存在不肯定的因素的函數。
優勢:
1)便於單獨測試; 2)輸入輸出的值結構固定,不易報錯且可預測;
缺點:
因爲結構固定,因此失去了js函數的靈活性和動態性;
demo:
redux中的reducer就是一個純函數形式;
不純函數:函數內部具備不肯定的因素存在,常見的因素有Math.random,異步操做,輸入輸出不肯定或者結構不相同等;
優勢:動態性比較好,靈活(開發中常常出現)
缺點:不便於預測返回的結果;
分離函數純度:
由於在平常的開發中,不純函數常常出現,主要是由於它不像純函數那樣到處受限制,相對靈活;然而正由於比較靈活,使得函數很差控制,處理很差就常常出現錯誤;因此能夠在不純函數中分離函數純度;
定義:將不純函數中純潔部分和不純部分分開處理;
作法:將純潔部分封裝在一個內部函數中,該內部函數就成爲不純函數的一個私有屬性;
demo:
const A = () => { const B = (a) => { return a + 1; } return Math.random + B(); }
函數式編程具備必定的優雅性和藝術性,不少優秀的前端框架都包含着大量的具備函數式編程 的思想。