javascript的currying函數
curring的概念將函數式編程的概念和默認參數以及可變參數結合在一起.一個帶n個參數,curried的函數固化第一個參數為固定參數,并返回另一個帶n-1個參數的函數對象,分別類似于LISP的原始函數car和cdr的行為。currying能泛化為偏函數應用(partial function application, PFA),p 這種函數將任意數量(順序)的參數的函數轉化為另一個帶剩余參數的函數對象。
最早期的curry函數有點多態的意味,就是根據函數參數在內部選用分支:
//http://www.openlaszlo.org/pipermail/laszlo-user/2005-March/000350.html
// ★★On 8 Mar 2005, at 00:06, Steve Albin wrote:
function add(a, b) {
if (arguments.length < 1) {
return add;
} else if (arguments.length < 2) {
return function(c) { return a + c }
} else {
return a + b;
}
}
var myadd = add( 2 );
var total = myadd(3);
日本的一個先行者可能在未搞清arguments也能用Array的原生方法轉換為數組的時候,用非常復雜的正則與eval搞出一個更接近現代currying意味的函數。
function curry(fun) {
if (typeof fun != 'function') {
throw new Error("The argument must be a function.");
}
if (fun.arity == 0) {
throw new Error("The function must have more than one argument.");
}
var funText = fun.toString();
var args = /function .*\((.*)\)(.*)/.exec(funText)[1].split(', ');
var firstArg = args.shift();
var restArgs = args.join(', ');
var body = funText.replace(/function .*\(.*\) /, "");
var curriedText =
"function (" + firstArg + ") {" +
"return function (" + restArgs + ")" + body +
"}";
eval("var curried =" + curriedText);
return curried;
}
接著是閉包的流行,與數組轉換arguments的技術的發現,現代currying函數終于粉墨登場,就好像15~17世紀大航海時代的地理大發現,javascript的世界突然間開闊了許多。
//一個簡單的現代currying函數
function curry (fn, scope) {
var scope = scope || window;
var args = [];
for (var i=2, len = arguments.length; i < len; ++i) {
args.push(arguments[i]);
};
return function() {
fn.apply(scope, args);
};
}
一般的currying函數只有兩重,執行情況如下,第一次執行參數不足返回內部函數,第二次執行才最終完成。不過針對這參數,我們還是可以做一些文章。看如下函數:
function sum(){
var result=0;
for(var i=0, n=arguments.length; i<n; i++){
result += arguments[i];
}
return result;
}
alert(sum(1,2,3,4,5)); // 15
這就沒有所謂的參數不足問題,傳入一個參數,它也計算。但不傳入參數呢?無錯,區別在于有沒有參數。我們可以讓它不斷執行自身,如果參數存在的情況下。最后在沒有參數的情況下,一次過執行。換言之,前面的步驟是用于儲存參數。
var sum2= curry(sum);
sum2= sum2(1)(2)(3)(4)(5);
sum2(); // 15
比起一般的currying函數,這有點難度。具體看注解:
var curry= function(fn){//原函數的參數為函數
return function(args){//內部函數的參數為數組,由于立即執行,因此直接到第三重去
//args是相對于第三重內部函數可是全局變量
var self= arguments.callee;//把自身保存起來(就是那個數組為參數的第二重函數)
return function(){ //這才是第二次調用的函數
if(arguments.length){//如果還有要添加的參數
[].push.apply(args,arguments);//apply把當前傳入的所有參數放進args中
return self(args);
}else{
return fn.apply(this,args);//apply的第二參數為數組
}
}
}([]);
};
機器瞎學/數據掩埋/模式混淆/人工智障/深度遺忘/神經掉線/計算機幻覺/專注單身二十五年
浙公網安備 33010602011771號