JS 淺談函數柯里化,不明覺厲

在計算機科學中,柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數且返回結果的新函數的技術。這個技術由 Christopher Strachey 以邏輯學家 Haskell Curry 命名的,儘管它是 Moses Schnfinkel 和 Gottlob Frege 發明的。閉包

柯里化函數思想

函數柯里化(function currying)又稱部分求值。一個currying的函數首先會接受一些參數,接受了這些參數後,該函數並不會當即求值,而是繼續返回另一個函數,剛纔傳入的參數在函數造成的閉包裏被保存起來。待到函數真正須要求值的時候,以前傳入的參數都會被一次性用於求值。app

假設咱們要編寫一個計算每個月開銷的函數。在天天結束以前,咱們都要記錄今天花了多少錢,代碼以下:函數

let result = 0;
let add = function(num){
  result += num;
  console.log(result);
}
add(10); // 10
add(5); // 15
add(8); // 23

這段代碼在天天結束後都會記錄並計算到今天爲止花了多少錢,但咱們不太關心天天花掉多少,只想知道月底總共花掉了多少,也就是說,只須要在月底計算一次。spa

若是在每月的前二十九天,咱們都只是保存好當天的開銷,直到第30天才進行求值計算,這就達到了咱們的目的。prototype

柯里化實現

  • 當函數調用有參數時,保存參數,做爲下次調用的參數
  • 當函數調用無參數時,計算結果

最終,咱們要實現這樣的方案,curry函數能夠屢次調用,每次調用的參數不定;當函數調用無參數時,輸出最終結果code

// curry - 柯里化函數
// fn - 計算結果的函數
// args - 參數
curry(fn, args...)(args...)(args...)(); 

廢話很少說,直接上代碼:blog

let add = function(){
  let args = Array.prototype.slice.call(arguments);
  let result = 0;
  args.forEach((item, key)=>{
    result += item;
  })
  console.log(result);
  return result;
}

let curry = function(fn){
  let args = Array.prototype.slice.call(arguments, 1);
  return function(){
    let args_add = Array.prototype.slice.call(arguments);
    let newArgs = args.concat(args_add);
    if(args_add.length){
      // 當函數調用無參數時,計算結果
      return curry.call(null, fn, ...newArgs);
    }else{
      // 當函數調用有參數時,保存參數,做爲下次調用的參數
      return fn.apply(null, newArgs);
    }
  }
}

curry(add, 1, 2)(4, 5)();  // 12

柯里化意義

一、延遲計算。(就像烹飪同樣,食材所有準備好後,廚師纔開始作菜)it

二、參數複用。當在屢次調用同一個函數,而且傳遞的參數絕大多數是相同的,那麼該函數多是一個很好的柯里化候選。io

三、動態建立函數。這能夠是在部分計算出結果後,在此基礎上動態生成新的函數處理後面的業務,這樣省略了重複計算。或者能夠經過將要傳入調用函數的參數子集,部分應用到函數中,從而動態創造出一個新函數,這個新函數保存了重複傳入的參數(之後沒必要每次都傳)console

 

歡迎你們指正嘍,哈哈

相關文章
相關標籤/搜索