前言
柯里化(Currying),又稱部分求值(Partial Evaluation),是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)
正文
簡(jiǎn)單柯里化
假設(shè)有一個(gè)數(shù)組,要對(duì)其中每一個(gè)元素進(jìn)行同樣操作,比如加一或加二
const arr1 = [0, 1, 2, 3];
let arr2 = arr1.map(e => e+1); //加一
let arr3 = arr1.map(e => e+2); //加二
那么是根據(jù)情況加不同的值,又不依賴全局變量,怎么處理,于是想把map里的1,2變成參數(shù),但是通過(guò)map無(wú)法傳遞該參數(shù),以下一個(gè)普通簡(jiǎn)單寫法
let func = function (arr,add) {
arr = arr.map(e => e + add)
return arr;
}
const arr1 = [0, 1, 2, 3];
let arr2 = func(arr1,3);
柯里化就是下面
let func = function (arr) {
return function (add) {
let arr_add = arr.map(e => e + add)
return arr_add;
}
}
const arr1 = [0, 1, 2, 3];
let arr2 = func(arr1)(3);
這是一種簡(jiǎn)單的柯里化,上面的func方法相當(dāng)于是一個(gè)函數(shù)工廠,返回的是一個(gè)函數(shù),也可以直接func2 = func(arr1),后面在靈活的根據(jù)某個(gè)值n執(zhí)行func2(n)來(lái)返回想要的數(shù)組
柯里化思想
柯里化部分求值,也就是延遲求值,等到需要的時(shí)候再求值
比如說(shuō)要做累加,使用一個(gè)很簡(jiǎn)單的全局變量就可以實(shí)現(xiàn),有一個(gè)專門的方法把傳參加到全局變量上,但這樣做當(dāng)數(shù)據(jù)量很大時(shí)會(huì)很耗費(fèi)資源,所以可以使用一個(gè)方法吧這些臨時(shí)值先全部收集起來(lái),等到我們想要實(shí)現(xiàn)運(yùn)算的時(shí)候再取執(zhí)行運(yùn)算
比如說(shuō)這樣:
let collect = (() => {
let arr = []; //做一個(gè)閉包來(lái)存儲(chǔ)值
return function () {
if (arguments.length === 0) { //開(kāi)始計(jì)算
let count = 0;
arr.forEach((v, k)=>{
count += v;
});
return count;
arr = null; //無(wú)用釋放
} else {
Array.prototype.push.apply(arr,arguments);
}
}
})();
collect(1);
collect(1);
collect(1.5);
console.log(collect()); //3.5
這不是一個(gè)真正柯里化,這段代碼是為了幫助理解柯里化延遲計(jì)算的思想
柯里化實(shí)現(xiàn)
目標(biāo):把類似collect(1,2,3,4)的方法按collect(1)(2)(3)(4)方式執(zhí)行,其實(shí)很像建造者模式, 在js里就相應(yīng)的使用閉包來(lái)模擬私有變量存儲(chǔ)這些參數(shù)
以下一段網(wǎng)上柯里化通用的方法
var curry = function (fn) {
var _args = []; //存儲(chǔ)參數(shù)待執(zhí)行
return function () {
if (arguments.length === 0) {
return fn.apply(this, _args);
}
Array.prototype.push.apply(_args, Array.prototype.slice.call(arguments));
return arguments.callee; //返回匿名函數(shù)
}
};
var collect = function () {
var total = 0;
for (var i = 0, c; c = arguments[i++];) {
total += c;
}
console.log(total);
}
var bulider = curry(collect); //來(lái)個(gè)類似builder的寫法
bulider = bulider(1);
bulider = bulider(1,2);
bulider = bulider(3);
bulider(); //7
var collect2 = curry(collect);
collect2(1)(2)(3)(); //6
柯里化的好處
- 參數(shù)復(fù)用;
- 提前返回;
- 延遲計(jì)算/運(yùn)行;