什麼是currying/柯里化
- 百度百科中是這麼解釋的:柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受餘下的參數且返回結果的新函數的技術。
- 忍者祕籍中是這麼解釋的:在一個函數中首先填充幾個參數(然後再返回一個新函數)的技術稱爲柯里化(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函數你們就可以看成另一種柯里化。