如何讀懂并寫出裝逼的函數(shù)式代碼?

對(duì)于函數(shù)式的版本,乍一看,的確令人非常費(fèi)解,仔細(xì)看一下,你可能就暈掉了,似乎完全就是天書,看上去非常裝逼,哈哈。不過,我感覺解析那段函數(shù)式的代碼可能會(huì)一個(gè)比較有趣過程。

先看代碼

這個(gè)代碼平淡無奇,就是從一個(gè)數(shù)組中找到一個(gè)數(shù),O(n)的算法,找不到就返回 null。

下面是正常的 old-school 的方式。不用多說。

結(jié)果到了函數(shù)式成了下面這個(gè)樣子(好像上面的那些代碼在下面若影若現(xiàn),不過又有點(diǎn)不太一樣,為了消掉if語言,讓其看上去更像一個(gè)表達(dá)式,動(dòng)用了 ? 號(hào)表達(dá)式):


為了講清這個(gè)代碼,需要先補(bǔ)充一些知識(shí)。

Javascript的箭頭函數(shù)

首先先簡(jiǎn)單說明一下,ECMAScript2015 引入的箭頭表達(dá)式。箭頭函數(shù)其實(shí)都是匿名函數(shù),其基本語法如下:

下面是一些示例:

看上去不復(fù)雜吧。不過,上面前兩個(gè) simple 和 max 的例子都把這箭頭函數(shù)賦值給了一個(gè)變量,于是它就有了一個(gè)名字。有時(shí)候,某些函數(shù)在聲明的時(shí)候就是調(diào)用的時(shí)候,尤其是函數(shù)式編程中,一個(gè)函數(shù)還對(duì)外返回函數(shù)的時(shí)候。比如下在這個(gè)例子:

其實(shí),在 MakePowerFn 函數(shù)里的那個(gè) PowerFn 根本不需要命名,完全可以寫成:

如果用箭頭函數(shù),可以寫成:

我們還可以寫得更簡(jiǎn)潔(如果用表達(dá)式的話,就不需要 { 和 }, 以及 return 語句 ):

我還是加上括號(hào),和換行可能會(huì)更清楚一些:

好了,有了上面的知識(shí),我們就可以進(jìn)入一個(gè)更高級(jí)的話題——匿名函數(shù)的遞歸。

匿名函數(shù)的遞歸

函數(shù)式編程立志于用函數(shù)表達(dá)式消除有狀態(tài)的函數(shù),以及for/while循環(huán),所以,在函數(shù)式編程的世界里是不應(yīng)該用for/while循環(huán)的,而要改用遞歸(遞歸的性能很差,所以,一般是用尾遞歸來做優(yōu)化,也就是把函數(shù)的計(jì)算的狀態(tài)當(dāng)成參數(shù)一層一層的往下傳遞,這樣語言的編譯器或解釋器就不需要用函數(shù)棧來幫你保存函數(shù)的內(nèi)部變量的狀態(tài)了)。

好了,那么,匿名函數(shù)的遞歸該怎么做?

一般來說,遞歸的代碼就是函數(shù)自己調(diào)用自己,比如我們求階乘的代碼:

在匿名函數(shù)下,這個(gè)遞歸該怎么寫呢?對(duì)于匿名函數(shù)來說,我們可以把匿名函數(shù)當(dāng)成一個(gè)參數(shù)傳給另外一個(gè)函數(shù),因?yàn)楹瘮?shù)的參數(shù)有名字,所以就可以調(diào)用自己了。?如下所示:

這個(gè)是不是有點(diǎn)作弊的嫌疑?Anyway,我們?cè)偻拢焉厦孢@個(gè)函數(shù)整成箭頭函數(shù)式的匿名函數(shù)的樣子。


現(xiàn)在你似乎就不像作弊了吧。把上面那個(gè)求階乘的函數(shù)套進(jìn)來是這個(gè)樣子:

首先,先重構(gòu)一下fact,把fact中自己調(diào)用自己的名字去掉:

然后,我們?cè)侔焉厦孢@個(gè)版本變成箭頭函數(shù)的匿名函數(shù)版:

這里,我們依然還要用一個(gè)fact來保存這個(gè)匿名函數(shù),我們繼續(xù),我們要讓匿名函數(shù)聲明的時(shí)候,就自己調(diào)用自己。

也就是說,我們要把?

這個(gè)函數(shù)當(dāng)成調(diào)用參數(shù),傳給下面這個(gè)函數(shù):

最終我們得到下面的代碼:

好像有點(diǎn)繞,anyway, 你看懂了嗎?沒事,我們繼續(xù)。

動(dòng)用高階函數(shù)的遞歸

但是上面這個(gè)遞歸的匿名函數(shù)在自己調(diào)用自己,所以,代碼中有hard code的實(shí)參。我們想實(shí)參去掉,如何去掉呢?我們可以參考前面說過的那個(gè)

我們可以看,上面的代碼簡(jiǎn)單說來就是,需要一個(gè)函數(shù)做參數(shù),然后返回這個(gè)函數(shù)的遞歸版本。那么,我們?cè)趺凑{(diào)用呢?

連起來寫就是:

但是,這樣讓用戶來調(diào)用很不爽,所以,以我們一個(gè)函數(shù)把?HighOrderFact ( HighOrderFact )?給代理一下:

用箭頭函數(shù)重構(gòu)一下,是不是簡(jiǎn)潔了一些?

上面就是我們最終版的階乘的函數(shù)式代碼。

回顧之前的程序

我們?cè)賮砜茨莻€(gè)查找數(shù)組的正常程序:

先把for干掉,搞成遞歸版本:

然后,寫出帶實(shí)參的匿名函數(shù)的版本(注:其中的if代碼被重構(gòu)成了 ?號(hào)表達(dá)式):

最后,引入高階函數(shù),去除實(shí)參:

注:函數(shù)式編程裝逼時(shí)一定要用const字符,這表示我寫的函數(shù)里的狀態(tài)是 immutable 的,天生驕傲!

再注:我寫的這個(gè)比原來版的那個(gè)簡(jiǎn)單了很多,原來版本的那個(gè)又在函數(shù)中套了一套 next, 而且還動(dòng)用了不定參數(shù),當(dāng)然,如果你想裝逼裝到天上的,理論上來說,你可以套N層,呵呵。

現(xiàn)在,你可以體會(huì)到,如此逼裝的是怎么來的了吧?




轉(zhuǎn)自:https://mp.weixin.qq.com/s/DYTAS5r5tFZyT-JotC4Pkg

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,703評(píng)論 0 1
  • 原文鏈接:https://github.com/EasyKotlin 值就是函數(shù),函數(shù)就是值。所有函數(shù)都消費(fèi)函數(shù),...
    JackChen1024閱讀 6,317評(píng)論 1 17
  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,927評(píng)論 0 5
  • 1.函數(shù)參數(shù)的默認(rèn)值 (1).基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。
    趙然228閱讀 829評(píng)論 0 0
  • 從未停止疏理自我 夢(mèng),期待,掙扎 ...... 時(shí)光不停地雕刻那一顆 混亂的心 終于 在暗灰的色彩里 青春向衰老臣...
    僞禰邇變閱讀 227評(píng)論 0 1

友情鏈接更多精彩內(nèi)容