函數(shù)式編程

函數(shù)式編程不是用函數(shù)來(lái)編程恋日,旨在將復(fù)雜的函數(shù)符合成簡(jiǎn)單的函數(shù)端壳。

1.函數(shù)是一等公民。所謂”第一等公民”(first class)佑吝,指的是函數(shù) 與其他數(shù)據(jù)類型一樣,處于平等地位鳖擒,可以賦值給其他變量溉浙,也 可以作為參數(shù),傳入另一個(gè)函數(shù)蒋荚,或者作為別的函數(shù)的返回值戳稽。

2..不可改變量。在函數(shù)式編程中期升,我們通常理解的變量在函數(shù)式 編程中也被函數(shù)代替了:在函數(shù)式編程中變量?jī)H僅代表某個(gè)表達(dá) 式惊奇。這里所說(shuō)的’變量’是不能被修改的。所有的變量只能被賦一次 初值 播赁。

3.map & reduce他們是常用的函數(shù)式編程的方法颂郎。

函數(shù)式編程常用核心概念:

1.純函數(shù)

??對(duì)于相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出容为,而且沒(méi)有任 何可觀察的副作用乓序,也不依賴外部環(huán)境的狀態(tài)。

var x = [1,2,3,4,5,6];
console.log(x.slice(0,3));  //[1,2,3]
console.log(x.slice(0,3));  //[1,2,3]
console.log(x.splice(0,3)); //[1,2,3]
console.log(x.splice(0,3)); //[4,5,6]

對(duì)于上述例子坎背,slice就是一個(gè)純函數(shù)替劈,而splice就不是,因?yàn)閮纱蔚玫降慕Y(jié)果不同得滤。

//不純的
var min = 18;
var checkage = age => age>min;

//純的
var checkage = age => age>18;

上面的例子陨献,不純是因?yàn)橐蕾嚵送獠孔兞縨in。
??但是上面的純函數(shù)有個(gè)問(wèn)題就是18被寫死了耿戚,這樣函數(shù)的擴(kuò)展性就比較差湿故,下面我們用柯里化來(lái)解決這個(gè)問(wèn)題。

2.函數(shù)的柯里化

??柯里化是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù)膜蛔,并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)坛猪。

對(duì)于前面說(shuō)的問(wèn)題,現(xiàn)用柯里化解決

var checkage = min => (age => age>min);
var checkage18 = checkage(18);
console.log(checkage18(20));    //true

// 上面的函數(shù)等價(jià)于
function checkage(min){
   return function(age){
       return age>min
    }
}
console.log(checkage(18)(20));

??事實(shí)上柯里化是一種“預(yù)加載”函數(shù)的方法皂股,通過(guò)傳遞較少的參數(shù)墅茉, 得到一個(gè)已經(jīng)記住了這些參數(shù)的新函數(shù),某種意義上講呜呐,這是一種 對(duì)參數(shù)的“緩存”就斤,是一種非常高效的編寫函數(shù)的方法。

3.函數(shù)組合

??純函數(shù)以及如何把它柯里化寫出的洋蔥代碼 h(g(f(x)))蘑辑, 為了解決函數(shù)嵌套的問(wèn)題洋机,我們需要用到“函數(shù)組合”:

const compose = (f,g) => (x =>f(g(x)));
var first = arr => arr[0];
var reverse = arr => arr.reverse();
var last = compose(first,reverse);
console.log(last([1,2,3,4,5]));    //5

//第一行代碼等價(jià)于
function compose(f,g){
    return function(x){
        return f(g(x));
    }
}
4.point Free

??point Free把一些對(duì)象自帶的方法轉(zhuǎn)化成純函數(shù),不要命名轉(zhuǎn)瞬即逝 的中間變量洋魂。

const compose = (f,g) => (x => f(g(x)));
var toUpperCase = word =>word.toUpperCase();
var split = x => (str => str.split(x));

var f = compose(split(''),toUpperCase);
console.log(f("abcd efgh"));    // ["A", "B", "C", "D", " ", "E", "F", "G", "H"]
5.聲明式與命令式代碼

?? 命令式代碼的意思就是绷旗,我們通過(guò)編寫一條又一條指令去讓計(jì)算 機(jī)執(zhí)行一些動(dòng)作喜鼓,這其中一般都會(huì)涉及到很多繁雜的細(xì)節(jié)。而聲 明式就要優(yōu)雅很多了衔肢,我們通過(guò)寫表達(dá)式的方式來(lái)聲明我們想干 什么庄岖,而不是通過(guò)一步一步的指示。

 //命令式 
let ceos= [];
for(var i = 0; i < companies.length; i++){   
    ceos.push(companies[i].ceo) 
} 

//聲明式 
let ceos = companies.map(c => c.ceo);

?? 函數(shù)式編程的一個(gè)明顯的好處就是這種聲明式的代碼角骤,對(duì) 于無(wú)副作用的純函數(shù)隅忿,我們完全可以不考慮函數(shù)內(nèi)部是如何實(shí) 現(xiàn)的,專注于編寫業(yè)務(wù)代碼邦尊。優(yōu)化代碼時(shí)背桐,目光只需要集中在 這些穩(wěn)定堅(jiān)固的函數(shù)內(nèi)部即可。
?? 相反胳赌,不純的函數(shù)式的代碼會(huì)產(chǎn)生副作用或者依賴外部系 統(tǒng)環(huán)境牢撼,使用它們的時(shí)候總是要考慮這些不干凈的副作用。在 復(fù)雜的系統(tǒng)中疑苫,這對(duì)于程序員的心智來(lái)說(shuō)是極大的負(fù)擔(dān)熏版。

6.惰性求值、惰性函數(shù)

?? 在指令式語(yǔ)言中以下代碼會(huì)按順序執(zhí)行捍掺,由于每個(gè)函數(shù) 都有可能改動(dòng)或者依賴于其外部的狀態(tài)撼短,因此必須順序 執(zhí)行。
??一旦我們接納了函數(shù)式哲學(xué)挺勿,惰性(或延遲)求值這一技術(shù)會(huì)變得非常有趣曲横。在討論并行時(shí)已經(jīng)見(jiàn)過(guò)下面的代碼片斷:

String s1 = somewhatLongOperation1();

String s2 = somewhatLongOperation2();

String s3 = concatenate(s1, s2);

?? 在一個(gè)命令式語(yǔ)言中求值順序是確定的,因?yàn)槊總€(gè)函數(shù)都有可能會(huì)變更或依賴于外部狀態(tài)不瓶,所以就必須有序的執(zhí)行這些函數(shù):首先是 somewhatLongOperation1禾嫉,然后 somewhatLongOperation2,最后 concatenate蚊丐,在函數(shù)式語(yǔ)言里就不盡然了熙参。
?? 前面提到只要確保沒(méi)有函數(shù)修改或依賴于全局變量,somewhatLongOperation1 和 somewhatLongOperation2 可以被并行執(zhí)行麦备。
?? 假設(shè)我們不想并行運(yùn)行這兩個(gè)函數(shù)孽椰,那是不是就按照字面順序執(zhí)行他們好了呢?答案是否定的凛篙,我們只在其他函數(shù)依賴于 s1 和 s2 時(shí)才需要執(zhí)行這兩個(gè)函數(shù)黍匾。我們甚至在 concatenate 調(diào)用之前都不必執(zhí)行他們——可以把他們的求值延遲到 concatenate 函數(shù)內(nèi)實(shí)際用到他們的位置。
?? 如果用一個(gè)帶有條件分支的函數(shù)替換 concatenate 并且只用了兩個(gè)參數(shù)中的一個(gè)呛梆,另一個(gè)參數(shù)就永遠(yuǎn)沒(méi)有必要被求值锐涯。在 Haskell 語(yǔ)言中,不確保一切都(完全)按順序執(zhí)行填物,因?yàn)?Haskell 只在必要時(shí)才會(huì)對(duì)其求值全庸。

7.高階函數(shù)

?? 函數(shù)當(dāng)參數(shù)秀仲,把傳入的函數(shù)做一個(gè)封裝融痛,然后返回這個(gè)封裝 函數(shù),達(dá)到更高程度的抽象壶笼。

//命令式
var add = function(a,b){
    return a+b;
}
function math(func,array){
    return func(array[0],array[1]);
}
math(add,[1,2]);    //3
8.尾調(diào)用優(yōu)化

??指函數(shù)內(nèi)部的后一個(gè)動(dòng)作是函數(shù)調(diào)用。該調(diào)用的返回值雁刷,直接返回給函數(shù)覆劈。。 函數(shù)調(diào)用自身沛励,稱為遞歸责语。如果尾調(diào)用自身,就稱為尾遞歸目派。遞歸需要保存大 量的調(diào)用記錄坤候,很容易發(fā)生棧溢出錯(cuò)誤,如果使用尾遞歸優(yōu)化企蹭,將遞歸變?yōu)檠?環(huán)白筹,那么只需要保存一個(gè)調(diào)用記錄,這樣就不會(huì)發(fā)生棧溢出錯(cuò)誤了谅摄。

//不是尾遞歸
function sum(n){
    if(n===1){
        return 1;
    }else{
        n+sum(n-1);
    }
}

其運(yùn)算過(guò)程如下:

sum(5)
(5+sum(4))
(5+(4+sum(3)))
(5+(4+(3+sum(2))))
(5+(4+(3+2+sum(1))))
(5+(4+(3+(2+1))))
(5+(4+(3+3)))
(5+(4+6))
(5+10)
15

//細(xì)數(shù)尾遞歸
function sum(x,total){
    if(x === 1){
        return x+toal;
    }else{
        return sum(x-1,x+total);
    }
}

其運(yùn)算過(guò)程如下:

sum(5,0)
sum(4,5)
sum(3,9)
sum(2,12)
sum(1,14)
15

??整個(gè)計(jì)算過(guò)程是線性的徒河,調(diào)用一次sum(x, total)后,會(huì)進(jìn)入下一個(gè)棧送漠,相關(guān)的數(shù)據(jù)信息和 跟隨進(jìn)入顽照,不再放在堆棧上保存。當(dāng)計(jì)算完后的值之后闽寡,直接返回到上層的 sum(5,0)代兵。這能有效的防止堆棧溢出。 在ECMAScript 6爷狈,我們將迎來(lái)尾遞歸優(yōu)化植影,通過(guò)尾遞歸優(yōu)化,javascript代碼在解釋成機(jī)器 碼的時(shí)候淆院,將會(huì)向while看起何乎,也就是說(shuō),同時(shí)擁有數(shù)學(xué)表達(dá)能力和while的效能土辩。

9.閉包

??閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)

10.范疇與容器

??我們可以把”范疇”想象成是一個(gè)容器支救,里面包含兩樣?xùn)|西。值 (value)拷淘、值的變形關(guān)系各墨,也就是函數(shù)。
??范疇論使用函數(shù)启涯,表達(dá)范疇之間的關(guān)系
??伴隨著范疇論的發(fā)展贬堵,就發(fā)展出一整套函數(shù)的運(yùn)算方法恃轩。這套方法 起初只用于數(shù)學(xué)運(yùn)算,后來(lái)有人將它在計(jì)算機(jī)上實(shí)現(xiàn)了黎做,就變成了今 天的”函數(shù)式編程"叉跛。
?? 本質(zhì)上,函數(shù)式編程只是范疇論的運(yùn)算方法蒸殿,跟數(shù)理邏輯筷厘、微積分、 行列式是同一類東西宏所,都是數(shù)學(xué)方法酥艳,只是碰巧它能用來(lái)寫程序。為 什么函數(shù)式編程要求函數(shù)必須是純的爬骤,不能有副作用充石?因?yàn)樗且环N 數(shù)學(xué)運(yùn)算,原始目的就是求值霞玄,不做其他事情骤铃,否則就無(wú)法滿足函數(shù) 運(yùn)算法則了。
??函數(shù)不僅可以用于同一個(gè)范疇之中值的轉(zhuǎn)換溃列,還可以用于將 一個(gè)范疇轉(zhuǎn)成另一個(gè)范疇劲厌。這就涉及到了函子(Functor)。
??函子是函數(shù)式編程里面重要的數(shù)據(jù)類型听隐,也是基本的運(yùn)算 單位和功能單位补鼻。它首先是一種范疇,也就是說(shuō)雅任,是一個(gè)容 器风范,包含了值和變形關(guān)系。比較特殊的是沪么,它的變形關(guān)系可 以依次作用于每一個(gè)值硼婿,將當(dāng)前容器變形成另一個(gè)容器

當(dāng)下函數(shù)式編程比較火熱的庫(kù)

RXJS*
cycleJS
lodashJS、lazy*
underscoreJS
ramdaJS*

資料:https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末禽车,一起剝皮案震驚了整個(gè)濱河市寇漫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殉摔,老刑警劉巖州胳,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異逸月,居然都是意外死亡栓撞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瓤湘,“玉大人瓢颅,你說(shuō)我怎么就攤上這事〕谒担” “怎么了挽懦?”我有些...
    開(kāi)封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)剃浇。 經(jīng)常有香客問(wèn)我巾兆,道長(zhǎng),這世上最難降的妖魔是什么虎囚? 我笑而不...
    開(kāi)封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮蔫磨,結(jié)果婚禮上淘讥,老公的妹妹穿的比我還像新娘。我一直安慰自己堤如,他們只是感情好蒲列,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著搀罢,像睡著了一般蝗岖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榔至,一...
    開(kāi)封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天抵赢,我揣著相機(jī)與錄音,去河邊找鬼唧取。 笑死铅鲤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枫弟。 我是一名探鬼主播邢享,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼淡诗!你這毒婦竟也來(lái)了骇塘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤韩容,失蹤者是張志新(化名)和其女友劉穎款违,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宙攻,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奠货,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了座掘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片递惋。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柔滔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萍虽,到底是詐尸還是另有隱情睛廊,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布杉编,位于F島的核電站超全,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏邓馒。R本人自食惡果不足惜嘶朱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望光酣。 院中可真熱鬧疏遏,春花似錦、人聲如沸救军。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)唱遭。三九已至戳寸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拷泽,已是汗流浹背疫鹊。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跌穗,地道東北人订晌。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蚌吸,于是被迫代替她去往敵國(guó)和親锈拨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容