【JS】高階函數(shù)與函數(shù)柯里化

高階函數(shù)

至少滿足以下條件的函數(shù):

柯里化(Currying)

什么是柯里化

柯里化是函數(shù)式編程中的一種進(jìn)階技巧踱蠢。

柯里化的直接表現(xiàn)形式就是焙格,當(dāng)我們有一個(gè)函數(shù)f(a,b,c),通過(guò)柯里化轉(zhuǎn)換崖瞭,使得這個(gè)函數(shù)可以被這樣調(diào)用f(a)(b)(c)狱杰。

柯里化有什么用途啊掏?

  • 參數(shù)可以復(fù)用暖混,便于封裝語(yǔ)法糖
    例如:系統(tǒng)中經(jīng)常有基礎(chǔ)的log方法莲镣,可以記錄不同時(shí)間的程序運(yùn)行信息,記錄具體的日志信息残拐。我們假設(shè)這個(gè)log方法調(diào)用一次途茫,就向后臺(tái)更新一條log記錄。
function log(date, importance, message) {
 $.post(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

比如我們現(xiàn)在要記錄當(dāng)天的日志信息:

log(new Date(), "DEBUG", "some debug"); 
log(new Date(), "DEBUG2", "some debug3"); 

我們會(huì)發(fā)現(xiàn)其實(shí)第一個(gè)參數(shù)是不變的溪食,只有后面的其他參數(shù)是變化的囊卜。
有了currying,我們可以這樣去調(diào)用:

let curryLog = curry(log);
let logNow = curryLog(new Date());
logNow("DEBUG2", "some debug3");

就減少了很多冗余代碼错沃。語(yǔ)義也更加清晰栅组。

一步一步實(shí)現(xiàn)Currying function

當(dāng)我們定義一個(gè)普通的函數(shù),分別傳入?yún)?shù)枢析,我們可以得到參數(shù)相加的結(jié)果笑窜。

function sum(a,b){
  return a+b;
}
sum(1,2);//3

現(xiàn)在我們希望可以把sum方法轉(zhuǎn)換一下,可以這樣被調(diào)用:

sum(1,2);//3
sum(1)(2);//3

初始實(shí)現(xiàn)思路

前置知識(shí):【JS】函數(shù)參數(shù)arguments與rest參數(shù)解析

  • arguments來(lái)保存參數(shù)
    因?yàn)閭魅氲膮?shù)數(shù)量是不確定的登疗,因此我們第一個(gè)思路就是借助JS當(dāng)中的arguments對(duì)象來(lái)實(shí)現(xiàn)排截。
  • 如果傳入的參數(shù)的個(gè)數(shù)小于被柯里化的函數(shù)定義的形式參數(shù)的個(gè)數(shù),那需要把傳入的參數(shù)保留下來(lái)辐益,并且要返回函數(shù)可以繼續(xù)接收下一個(gè)參數(shù)断傲。

遞歸實(shí)現(xiàn)法

function sum(a, b,c) {
  return a + b + c;
}
function curried(fn) {
  var slice = Array.prototype.slice;
  var outer = slice.call(arguments,1);
  return function(){
    var inner = slice.call(arguments);
    var args = outer.concat(inner);
    console.log('args',args);
    return fn.apply(this,args);
  }
}
function curry(fn,length) {
  var slice = Array.prototype.slice;
  let len = length | fn.length;
  return function () {
    // arguments.length是傳入的實(shí)參的數(shù)量
    //fn.length是函數(shù)形參的數(shù)量
    if (arguments.length < len) {
      // 如果被柯里化后的函數(shù)調(diào)用時(shí),實(shí)參的數(shù)量少于fn形參的數(shù)量
      var combined = [fn].concat(slice.call(arguments));
      // 就需要把參數(shù)保存下來(lái)智政,并且能夠繼續(xù)返回一個(gè)函數(shù)认罩,接收后續(xù)的參數(shù)
      console.log('combined', combined);
      var sub = curried.apply(this, combined);
      console.log('curried', sub);
      return curry(sub, len - arguments.length);
    } else {
      return fn.apply(this,arguments);
    }
  }
}
var currySum = curry(sum);
console.log(currySum(1)(2)(3));
// output:
//combined (2) [?, 1]
//curried ? (){
//     var inner = slice.call(arguments);
//     var args = outer.concat(inner);
//     console.log('args',args);
//     return fn.apply(this,args);
//   }
// combined (2) [?, 2]
// curried ? (){
//     var inner = slice.call(arguments);
//     var args = outer.concat(inner);
//     console.log('args',args);
//     return fn.apply(this,args);
//   }
//  args (2) [2, 3]
//  args (3) [1, 2, 3]
//  6

從console出的結(jié)果我們可以看出來(lái),每次調(diào)用的參數(shù)都被保存起來(lái)了续捂。
curry函數(shù)中垦垂,length參數(shù)作為遞歸結(jié)束的條件宦搬,每保存一個(gè)參數(shù),就把長(zhǎng)度相應(yīng)減少劫拗。
curried函數(shù)用來(lái)返回嵌套的函數(shù)间校,通過(guò)組合內(nèi)層和外層的參數(shù),把參數(shù)保留起來(lái)页慷。
當(dāng)遞歸結(jié)束的時(shí)候憔足,arguments里面就包含了所有的參數(shù)。
JavaScript專題之函數(shù)柯里化
js-info_Currying

循環(huán)實(shí)現(xiàn)法

function curry(fn, args) {
    var len = fn.length;
    args = args || [];
    return function() {
      var _args = args.slice(0);
      //把所有arguments保存下來(lái)
      _args = _args.concat(Array.prototype.slice.call(arguments));
      if (_args.length < len) {
          return curry.call(this, fn, _args);
      }
      else {
          return fn.apply(this, _args);
      }
    }
}

Rest參數(shù)解法

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));
      }
    }
  };
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酒繁,一起剝皮案震驚了整個(gè)濱河市滓彰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌州袒,老刑警劉巖揭绑,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異郎哭,居然都是意外死亡他匪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)彰居,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诚纸,“玉大人撰筷,你說(shuō)我怎么就攤上這事陈惰。” “怎么了毕籽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵抬闯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我关筒,道長(zhǎng)溶握,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任蒸播,我火速辦了婚禮睡榆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袍榆。我一直安慰自己胀屿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布包雀。 她就那樣靜靜地躺著宿崭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪才写。 梳的紋絲不亂的頭發(fā)上葡兑,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天奖蔓,我揣著相機(jī)與錄音,去河邊找鬼讹堤。 笑死吆鹤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜕劝。 我是一名探鬼主播檀头,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岖沛!你這毒婦竟也來(lái)了暑始?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤婴削,失蹤者是張志新(化名)和其女友劉穎廊镜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體唉俗,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗤朴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虫溜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雹姊。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖衡楞,靈堂內(nèi)的尸體忽然破棺而出吱雏,到底是詐尸還是另有隱情,我是刑警寧澤瘾境,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布歧杏,位于F島的核電站,受9級(jí)特大地震影響迷守,放射性物質(zhì)發(fā)生泄漏犬绒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一兑凿、第九天 我趴在偏房一處隱蔽的房頂上張望凯力。 院中可真熱鬧,春花似錦礼华、人聲如沸咐鹤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)慷暂。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間行瑞,已是汗流浹背奸腺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留血久,地道東北人突照。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像氧吐,于是被迫代替她去往敵國(guó)和親讹蘑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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