參考書籍:《javascript 函數(shù)式編程》
什么是函數(shù)式編程?
函數(shù)式編程通過函數(shù)將值轉(zhuǎn)換為抽象單元,接著用于構(gòu)建軟件系統(tǒng)。
函數(shù)式編程技術(shù)有什么?
- 確定抽象,并為其構(gòu)建函數(shù)
- 利用已有的函數(shù)來構(gòu)建更為復(fù)雜的抽象
- 通過將現(xiàn)有的函數(shù)傳給其他的函數(shù)來構(gòu)建更加復(fù)雜的抽象
為什么函數(shù)式編程很重要?
首先先從面向?qū)ο蟮慕嵌葋碇v,我們主要目標(biāo)會(huì)將問題分解。如圖所示。

把這些對(duì)象聚集起來,組合成更大的部件

從圖中不難看出,里面有很多重復(fù)的函數(shù),因?yàn)槊嫦驅(qū)ο?,所以?huì)著重于解決每個(gè)組件里的需求。
相比較而言,嚴(yán)格的函數(shù)式編程也會(huì)將一個(gè)問題分為幾部分函數(shù)來解決。

與面向?qū)ο缶幊填愃疲瘮?shù)式編程也通過“黏結(jié)”或“組合”其他函數(shù)的方式來構(gòu)建更大的函數(shù),實(shí)現(xiàn)更加抽象的行為。

在一個(gè)面向?qū)ο笙到y(tǒng)的內(nèi)部,我們會(huì)發(fā)現(xiàn)對(duì)象之間的交互會(huì)引起各個(gè)對(duì)象內(nèi)部狀態(tài)的變化,而整個(gè)系統(tǒng)的變化就是由這些狀態(tài)變化混合來形成的。
相比之下,函數(shù)式編程系統(tǒng)則努力減少可見的狀態(tài)修改。
函數(shù)式編程以命令的方式構(gòu)建系統(tǒng),并通過顯性的狀態(tài)改變縮減到最小來變得更加模塊化。實(shí)踐中的函數(shù)式編程不是以消除狀態(tài)改變?yōu)槟康?,而是將已知系統(tǒng)中突變盡量縮小到最小區(qū)域中
以函數(shù)為抽象單元
抽象方法是指隱藏了實(shí)現(xiàn)細(xì)節(jié)的函數(shù)。
//未隱藏細(xì)節(jié)的函數(shù)
function parseAge(age) {
if (!_.isString(age)) throw new Error('Expecting a string');
var a;
console.log("Attempting to parse an age");
a = parseInt(age, 10);
if(_.isNaN(a)) {
console.log(["Could not parse age:", age].join(' '));
a = 0;
}
return a;
}
//隱藏細(xì)節(jié)
function fail(thing) {
throw new Error(thing);
}
function warn(thing) {
console.log(["WARNING", thing].join(' '));
}
function note(thing) {
console.log(["NOTE", thing].join(' '));
}
function parseAge(age) {
if(!_.isString(age)) fail("Expecting a string");
var a;
note("Attempt to parse an age");
a = parseInt(age, 10);
if(_.isNaN(a)) {
warn(["Could not parse age:", age].join(' '));
a = 0;
}
return a;
}
對(duì)比上述代碼,其實(shí)現(xiàn)的功能其實(shí)是一樣的,不同的是現(xiàn)在報(bào)告錯(cuò)誤、信息和警告的想法已經(jīng)被抽象化了。這樣在修改輸出錯(cuò)誤、信息和警告呈現(xiàn)的方式,就不用修改相應(yīng)的代碼行,以及其他地方的類似輸出模式,而是直接添加錯(cuò)誤函數(shù)的參數(shù)。
封裝和隱藏
在面向?qū)ο笾?,封裝是指一種將若干個(gè)數(shù)據(jù)與用來操縱它們的特定操作包裝起來的方式。比如說新建一個(gè)對(duì)象,就可以包含一個(gè)數(shù)組及操縱這個(gè)數(shù)組的push、pop方法,這就是封裝。
然而,有時(shí)在限制元素的可見性時(shí)也會(huì)用到封裝,這個(gè)時(shí)候就稱為數(shù)據(jù)隱藏,在js中就使用閉包來隱藏?cái)?shù)據(jù)(閉包有好有壞,使用需慎重,否則很容易把自己搞暈,并且可能會(huì)使代碼可讀性變差。)
以函數(shù)為行為單元
就是用函數(shù)來進(jìn)行簡(jiǎn)單的存儲(chǔ)和傳遞基本行為,函數(shù)命名通常會(huì)讓人一目了然知道該函數(shù)得到的結(jié)果,發(fā)出的行為。比如sort函數(shù),就會(huì)知道是分類的函數(shù)。
數(shù)據(jù)抽象
函數(shù)式編程旨在用最簡(jiǎn)單的數(shù)據(jù)來實(shí)現(xiàn)高層級(jí)的行為。在代入簡(jiǎn)單數(shù)據(jù)后最終實(shí)現(xiàn)復(fù)雜的行為 。

我們會(huì)發(fā)現(xiàn),在處理與人有關(guān)的數(shù)據(jù)時(shí)更適合用函數(shù)式編程的方式,而面向?qū)ο蟮姆椒ǜm合與模擬人。
函數(shù)式編程速度。。
在函數(shù)式編程中經(jīng)常會(huì)把各種行為抽象出來成為單獨(dú)的函數(shù),然后再組合起來執(zhí)行。這樣在我們之前講到的Event loop線程中我們會(huì)感動(dòng)困惑,因?yàn)樵趈avascript中那樣事件一次一次掛載起來執(zhí)行的話速度可能會(huì)很慢。
嗯,是的,應(yīng)該是會(huì)這樣的。因此,在一些把速度作為第一要領(lǐng)比如游戲界面的網(wǎng)站我們會(huì)更傾向于使用面向?qū)ο缶幊?/strong>。
然而在一些復(fù)雜度較高,項(xiàng)目較為龐大的時(shí)候,使用函數(shù)式編程則會(huì)讓我們的代碼可讀性增強(qiáng),而且處理數(shù)據(jù)的時(shí)候出錯(cuò)的可能性更低。