函數(shù)式編程:柯理化函數(shù)和組合函數(shù)

柯理化函數(shù)和組合函數(shù)都?xì)w屬于函數(shù)式編程蟀瞧,用于解決函數(shù)式編程的問題

首先先說明一下函數(shù)式編程和面向?qū)ο笫骄幊痰膬?yōu)缺點
* 面向?qū)ο缶幊痰?    優(yōu)點
        程序更加便于分析怠噪、設(shè)計、理解
        是易拓展的获洲,由于繼承、封裝塘秦、多態(tài)的特性定踱,
        自然設(shè)計出高內(nèi)聚筷狼、低耦合的系統(tǒng)結(jié)構(gòu)瓶籽,使得系統(tǒng)更靈活、更容易擴展埂材,而且成本較低
    缺點
        為了寫可重用的代碼而產(chǎn)生了很多無用的代碼塑顺,導(dǎo)致代碼膨脹

* 函數(shù)式編程的
    優(yōu)點
        代碼可讀性更強。
        實現(xiàn)同樣的功能函數(shù)式編程所需要的代碼比面向?qū)ο缶幊桃俸芏啵?        代碼更加簡潔明晰
        開發(fā)速度快
    缺點
        所有的變量在程序運行期間都是一直存在的俏险,非常占用運行資源

柯理化函數(shù)currying

  • 概念:是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù)严拒,并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。

示例:

//普通函數(shù)
function add(n1, n2) {
    return n1 + n2
}
add(1, 2)


//柯理化函數(shù)
function add(n1) {//把參數(shù)一個一個的傳入
    return function (n2) {//返回帶著返回結(jié)果的新函數(shù)
        return n1 + n2
    }
}
add(1)(2);
  • 為什么使用柯理化函數(shù)
    柯理化就是利用模塊化思想處理多參函數(shù)竖独,通過組合函數(shù)減少每個函數(shù)的入?yún)?shù)量裤唠,從而提高代碼的可閱讀性及可維護性。

創(chuàng)建一個柯理化函數(shù)

function currying(fun) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var _args = args.concat(Array.prototype.slice.call(arguments));
        return fun.apply(null, _args);
    }
}

利用柯理化函數(shù)改造一個函數(shù)

function add(...vals){
    return vals.reduce((pre, val) = > {
            return pre + val;
    });
}

var newAdd = currying(add, 1, 2, 3);
console.log(newAdd(4, 5, 6)); // 21

但是上邊封裝的柯理化函數(shù)的代碼莹痢,只能使用一次种蘸,不能夠多次執(zhí)行

function currying(fn) {
    var args = [].slice.call(arguments, 1);
    return function () {
        if (arguments.length == 0) {
            return fn.apply(null, args);//如果不帶參數(shù)調(diào)用,就說明參數(shù)已經(jīng)傳完了竞膳,要返回結(jié)果了
        } else {
            args = args.concat([].slice.call(arguments));//如果調(diào)用時帶著參數(shù)航瞭,只需要把參數(shù)添加進去,利用不銷毀作用域坦辟,下次再調(diào)用的時候就包含上次傳遞的參數(shù)了
        }
    }
}

多次調(diào)用

function add() {
    var vals = Array.prototype.slice.call(arguments);
    return vals.reduce((pre, val) = > {
            return pre + val;
    });
}
var newAdd = currying(add, 1, 2, 3);
newAdd(4, 5);
newAdd(6, 7);
console.log(newAdd());  // 28
//把每次函數(shù)調(diào)用的參數(shù)都存儲起來刊侯,如果已無參形式調(diào)用,說明記錄結(jié)束锉走,需要做最終計算滨彻。

高級柯理化函數(shù)

function sum(a, b, c) {
  return a + b + c;
}
sum(1,2,3)
//想實現(xiàn)一個柯理化函數(shù)
let curried= curry(sum);
curried(1,2,3) //6
curried(1)(2,3) //6
curried(1)(2)(3) //6
function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  };
}
//如果傳入的參數(shù)個數(shù)的和一直小于原函數(shù)的個數(shù)就遞歸執(zhí)行,直到參數(shù)全部執(zhí)行完就調(diào)用原函數(shù)

偏函數(shù)和柯理化函數(shù)的概念及區(qū)別

  • 當(dāng)把已知函數(shù)的一些參數(shù)固定挪蹭,結(jié)果函數(shù)被稱為偏函數(shù)亭饵,通過使用bind獲得偏函數(shù),也有其他方式實現(xiàn)嚣潜。
    eg: 當(dāng)我們不想一次一次重復(fù)相同的參數(shù)時冬骚,偏函數(shù)是很便捷的。如我們有send(from,to)函數(shù)懂算,如果from總是相同的只冻,可以使用偏函數(shù)簡化調(diào)用。
  • 柯里化是轉(zhuǎn)換函數(shù)調(diào)用從f(a,b,c)至f(a)(b)(c).Javascript通常既實現(xiàn)正常調(diào)用计技,也實現(xiàn)參數(shù)數(shù)量不足時的偏函數(shù)方式調(diào)用喜德。

組合函數(shù)compose

簡單來說,就是把很多函數(shù)組合到一起垮媒,執(zhí)行一個函數(shù)舍悯,所有的函數(shù)都執(zhí)行了

  • 將函數(shù)串聯(lián)起來執(zhí)行航棱,將多個函數(shù)組合起來,一個函數(shù)的輸出結(jié)果是另一個函數(shù)的輸入?yún)?shù)萌衬,一旦第一個函數(shù)開始執(zhí)行饮醇,就會像多米諾骨牌一樣推導(dǎo)執(zhí)行了。
  • 特點
    compose的參數(shù)是函數(shù)秕豫,返回的也是一個函數(shù)
    因為除了第一個函數(shù)的接受參數(shù)朴艰,其他函數(shù)的接受參數(shù)都是上一個函數(shù)的返回值
    compsoe函數(shù)可以接受任意的參數(shù),所有的參數(shù)都是函數(shù)混移,且執(zhí)行方向是自右向左的祠墅,初始函數(shù)一定放到參數(shù)的最右面

示例

var greeting = (firstName, lastName) =>'hello,  ' + firstName + '  ' + lastName + '   ';
var toUpper = str =>str.toUpperCase();
var fn = compose(toUpper, greeting);//從右向左執(zhí)行
//只有g(shù)reeting接受參數(shù)'jack', 'smith',toUpper 接受的參數(shù)是greeting的返回值
console.log(fn('jack', 'smith'))// ‘HELLO歌径,JACK SMITH’

我使用的reduce實現(xiàn)的compose

function compose(){
   let args=[].slice.call(arguments);
   var length = args.length;
   var index = length;
   while (index--) {//如果參數(shù)中存在不是函數(shù)類型的值毁嗦,就拋出錯誤
        if (typeof args[index] !== 'function') {
            throw new TypeError('Expected a function');
        }
    }
   let last=args.pop();
   args=args.reverse();
   return function (){
       let _args = [].slice.call(arguments);
       return args.reduce((prev, next)=>{
          return next(prev);//每一個函數(shù)執(zhí)行的返回值都作為上一個函數(shù)的參數(shù)傳進去
       },last.apply(null,_args))//最后一個函數(shù)是需要傳值的
   }
}

繼續(xù)執(zhí)行

var trim = str =>str.replace(/\s+/g, '|');
var newFn = compose(trim, fn);
console.log(newFn('jack', 'smith'));
  • loadsh的flow / flowRight實現(xiàn) (利用while循環(huán))
    flow 返回一個函數(shù),連續(xù)調(diào)用參數(shù)中傳遞的函數(shù)數(shù)組
    //lodash的實現(xiàn) 從左向右執(zhí)行的函數(shù)
var flow = function (funcs) {
    var length = funcs.length;
    var index = length
    while (index--) {
        if (typeof funcs[index] !== 'function') {
            throw new TypeError('Expected a function');
        }
    }
    return function (...args){
        var index = 0
        var result = length ? funcs[index].apply(this, args) : args[0]
        while (++index < length) {
            result = funcs[index].call(this, result)
        }
        return result
    }
}
var flowRight = function (funcs) {
    return flow(funcs.reverse())
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末回铛,一起剝皮案震驚了整個濱河市狗准,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌勺届,老刑警劉巖驶俊,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異免姿,居然都是意外死亡,警方通過查閱死者的電腦和手機榕酒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門胚膊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人想鹰,你說我怎么就攤上這事紊婉。” “怎么了辑舷?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵喻犁,是天一觀的道長。 經(jīng)常有香客問我何缓,道長肢础,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任碌廓,我火速辦了婚禮传轰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谷婆。我一直安慰自己慨蛙,他們只是感情好辽聊,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著期贫,像睡著了一般跟匆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上通砍,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天贾铝,我揣著相機與錄音,去河邊找鬼埠帕。 笑死垢揩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敛瓷。 我是一名探鬼主播叁巨,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼呐籽!你這毒婦竟也來了锋勺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤狡蝶,失蹤者是張志新(化名)和其女友劉穎庶橱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贪惹,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡攻臀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贡耽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲁捏。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖硼端,靈堂內(nèi)的尸體忽然破棺而出并淋,到底是詐尸還是另有隱情,我是刑警寧澤珍昨,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布县耽,位于F島的核電站,受9級特大地震影響镣典,放射性物質(zhì)發(fā)生泄漏兔毙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一骆撇、第九天 我趴在偏房一處隱蔽的房頂上張望瞒御。 院中可真熱鬧,春花似錦神郊、人聲如沸肴裙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜻懦。三九已至甜癞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宛乃,已是汗流浹背悠咱。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留征炼,地道東北人析既。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像谆奥,于是被迫代替她去往敵國和親眼坏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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

  • 原文鏈接:https://github.com/EasyKotlin 值就是函數(shù)酸些,函數(shù)就是值宰译。所有函數(shù)都消費函數(shù),...
    JackChen1024閱讀 5,944評論 1 17
  • 函數(shù)和對象 1魄懂、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念沿侈。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,525評論 0 5
  • 感謝社區(qū)中各位的大力支持市栗,譯者再次奉上一點點福利:阿里云產(chǎn)品券缀拭,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大獎:點擊這里領(lǐng)取 至...
    HetfieldJoe閱讀 876評論 0 2
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,367評論 0 5
  • 第5章 函數(shù)和函數(shù)式編程 5.1 引言函數(shù)是組織好的肃廓,可重復(fù)使用的智厌,用來實現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段盲赊。函數(shù)...
    VIVAFT閱讀 947評論 0 5