內容來自曾探,《JavaScript設計模式與開發實踐》,P49
函數柯里化(function currying)又稱部分求值。一個currying的函數首先會接受一些參數,接受了這些參數后,該函數並不會立即求值,而是繼續返回另外一個函數,剛才傳入的參數在函數形成的閉包里被保存起來。待到函數真正需要求值的時候,之前傳入的參數都會被一次性用於求值。
假設我們要編寫一個計算每月開銷的函數。在每天結束之前,我們都要記錄今天花了多少錢,代碼如下:
var monthlyCost = 0; var cost = function(money){ monthlyCost += money; }; cost(100);//第一天開銷 cost(200);//第二天開銷 cost(300);//第三天開銷 //cost(700);//第三十天開銷 alert(monthlyCost);//輸出:600
這段代碼在每天結束后都會記錄並計算到今天為止花了多少錢,但我們不太關心每天花掉多少,只想知道月底總共花掉了多少,也就是說,只需要在月底計算一次。
如果在每個月的前二十九天,我們都只是保存好當天的開銷,直到第30天才進行求值計算,這就達到了我們的目的。下面的代碼還不是一個currying函數的完整實現,但有助於我們了解其思想:
var cost = (function(){ var args = []; return function(){ if(arguments.length === 0){ var money = 0; for(var i = 0, l = args.length; i < l; i++){ money += args[i]; } return money; }else{ [].push.apply(args, arguments); } } }()); cost(100);//未真正求值 cost(200);//未真正求值 cost(300);//未真正求值 console.log(cost());//求值並輸出:600
接下來編寫一個通用的function currying(){},它接受一個參數,即將要被currying的函數。在這個例子里,這個函數的作用是遍歷本月每天的開銷並求出它們的總和。代碼如下:
var currying = function(fn){ var args = []; return function(){ if(arguments.length === 0){ return fn.apply(this, args); }else{ [].push.apply(args, arguments); return arguments.callee; } } };
var cost = (function(){ var money = 0; return function(){ for(var i = 0, l = arguments.length; i < l; i++){ money += arguments[i]; } return money; } }()); var cost = currying(cost);//轉化為currying函數 cost(100);//未真正求值 cost(200);//未真正求值 cost(300);//未真正求值 console.log(cost());//求值並輸出:600
至此,我們完成了一個currying函數的編寫,當調用cost()時,如果明確帶上參數,表明此時並不進行真正的求值計算,而是把這些參數保存起來,此時讓cost()函數返回另外一個函數。只有當我們以不帶參數的形式執行cost()時,才利用前面保存的所有參數,真正開始求值計算。
內容來自曾探,《JavaScript設計模式與開發實踐》,P49