1. 程式人生 > >函式的柯里化

函式的柯里化

看了不少大佬的文章,終於對柯里化有了初步的理解,簡單總結一下。
什麼是柯里化?
在電腦科學中,柯里化(Currying)是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數且返回結果的新函式的技術。
看了概念還是一頭霧水,用程式碼解釋一下。
例如有一個簡單的加法運算:

function add(a,b,c){
    return a+b+c
}
add(1,2,3);   //這是接受多個引數的函式

現在把它變換成接受單一引數的柯里化函式

function add(a){
  return function(b){
    return function(c){
       return a+b+c
    }
  }
}
add(1)(2)(3);   //接受單一引數

柯里化函式結合了閉包的用法,不瞭解閉包的先學習閉包噢
柯里化把簡單的問題複雜化了,同時把複雜的問題自由化了,來看這麼一個例子:

// 實現一個add方法,使計算結果能夠滿足如下預期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4,5) = 15;

這個題目的難點在於引數的不確定,所以要封裝一個函式來運算。

function add(){
	//debugger;
    var args = [].slice.call(arguments);
    var fn = function(){
        var newArgs = args.concat([].slice.call(arguments));
        return add.apply(null,newArgs);   //null表示window
    } 
    fn.toString = function(){     //toString()重寫函式
        return args.reduce(function(a, b) {   
        //reduce() 方法接收一個函式作為累加器
            return a + b;
        })
    }
    return fn ;
}
 add(1)(2)(3);    //f 6
 add(1, 2, 3)(4);   //f 10
 add(1)(2)(3)(4,5) ;  //f 15
 add(1)(2)(3).toString();   //6

函式有些難理解,建議debugger在瀏覽器看執行步驟。

柯里化的應用場景
手機號、郵箱的驗證,我們一般會寫一個通用的函式,將用於驗證的正則和將要被驗證的字串作為引數傳入。

function check(reg,targetString){
    return reg.test(targetString);
}

這樣使用會有點冗餘,每次都要重複寫正則表示式

check(/^1[34578]\d{9}$/, '14900000088');
check(/^1[34578]\d{9}$/, '13714357188');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '
[email protected]
'); check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]');

柯里化函式的執行過程其實是一個引數的收集過程,我們將每一次傳入的引數收集起來,並在最裡層處理,所以可以藉助這個思路來封裝一下。

function createCurry(func, args) {
    var arity = func.length;    //2      check函式形參的長度
    var args = args || [];
    return function() {
        var newArgs = [].slice.call(arguments);
        [].push.apply(newArgs, args);   //args引數push進newArgs
       // 如果引數個數小於最初的func.length,則遞迴呼叫,繼續收集引數
        if (newArgs .length < arity) {
            return createCurry.call(this, func, newArgs);
        }
        // 引數收集完畢,則執行func
        return func.apply(this, newArgs );
    }
}
var checkPhone = createCurry(check)(/^1[34578]\d{9}$/);
var checkEmail =  createCurry(check)(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);

最後呼叫就會更加簡潔了。

checkPhone('14900000088');
checkPhone('13714357188');
checkEmail('[email protected]');

參考資料:https://www.jianshu.com/p/5e1899fe7d6b