淺談JavaScript函數柯里化

什麼是currying/柯里化


  1. 百度百科中是這麼解釋的:柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受餘下的參數且返回結果的新函數的技術。
  2. 忍者祕籍中是這麼解釋的:在一個函數中首先填充幾個參數(然後再返回一個新函數)的技術稱爲柯里化(Currying)。

如果看這些概念你不是特別清楚那麼我們接下來看一個實例:

let add1 = function(a,b,c){
    return a+b+c;
}
let add2 = function(a){//函數柯里化
    return function(b){
        return function(c){
            return a+b+c;
        }
    }
}
console.log(add1(1,2,3));//6
console.log(add2(1)(2)(3));//6

是不是感覺和閉包有點類似,恩 其實實質利用的就是閉包的概念,本質上講柯里化(Currying)只是一個理論模型,柯里化所要表達是:如果你固定某些參數,你將得到接受餘下參數的一個函數。

柯里化實例


當然,柯里化的參數是不固定的,假設我現在有n個數需要求和操作我們應該怎麼寫

let add = function () {
    let _args = [];
    return function () {
        if (arguments.length === 0) {
            return _args.reduce(function (a, b) {
                return a + b;
            });
        }
        [].push.apply(_args, [].slice.call(arguments));
        return arguments.callee;
    }
   };
let sum = add()

sum(1,2)(3);    // 調用形式靈活,一次調用可輸入一個或者多個參數
console.log(sum());   // 6(最後在進行計算輸出) 

上面 add是柯里化了的函數,它返回一個新的函數,新的函數可接收新的參數,延遲到最後一次計算。

基礎知識講解


arguments

函數有個內置的對象 arguments 對象。argument 對象包含了函數調用的參數數組。

arguments.callee

arguments.callee該屬性是一個指針,指向擁有這個arguments對象的函數。由於嚴格模式下不能使用arguments.callee所以,我們可以改進一下上面的add函數。

let add = function () {
    let _args = [];
    return function fn () {
        if (arguments.length === 0) {
            return _args.reduce(function (a, b) {
                return a + b;
            });
        }
        [].push.apply(_args, [].slice.call(arguments));
        return fn;
    }
   };
let sum = add()

sum(1,2)(3);    // 調用形式靈活,一次調用可輸入一個或者多個參數
console.log(sum());   // 6(最後在進行計算輸出) 

[].push.apply(_args, [].slice.call(arguments));

這個方法等同於Array.prototype.push.apply(_args,Array.prototype.slice.call(arguments));這個方法實現了將arguments合併到 _args中與 _args = _args.concat([].slice.call(arguments));類似。

封裝柯里化函數


我們既然知道了柯里化函數是什麼,那麼我們可以將它封裝成一個函數

let currying = function (callback){//參數中放入一個回調函數
    let _args = [];//聲明一個參數數組
    return function fn(){
        if(arguments.length===0){
            return callback.apply(this,_args);
        }
        _args = _args.concat([].slice.call(arguments));
        return fn;
    }
};

使用

let add = function () {
    let sum = 0;
    for (let i = 0, c; c = arguments[i++];) {
        sum += c;
    }
    return sum;
};

let sum = currying(add);

sum(1,2)(3);
console.log(sum());//6

當然,當大家看到這裏時是不是覺得柯里化好像在平時用不上,那麼大家覺得bind函數用的多嗎?其實bind函數你們就可以看成另一種柯里化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章