概念
柯里化可以讓我們給函數(shù)傳遞較少的參數(shù)得到一個(gè)已經(jīng)記住的某個(gè)固定參數(shù)的新函數(shù)
這是一種對(duì)函數(shù)參數(shù)的緩存
讓函數(shù)變的更靈活棺牧,讓函數(shù)的粒度更小
-
可以把多元函數(shù)(指多個(gè)參數(shù))轉(zhuǎn)化成一元函數(shù)(指一個(gè)參數(shù))欢嘿,可以組合使用函數(shù),使其產(chǎn)生強(qiáng)大的功能
這是一種預(yù)先處理的思想(形成一個(gè)不被釋放的閉包稻轨,把一些信息存儲(chǔ)起來(lái),以后基于作用域鏈,訪問(wèn)到事先存儲(chǔ)的信息羞酗,然后進(jìn)行相關(guān)的處理,所有符合這種模式都被成為柯里化函數(shù))
先來(lái)看看 reduce
數(shù)組 reduce 方法:在遍歷數(shù)組的過(guò)程中紊服,可以積累上一次處理的結(jié)果檀轨,基于上次處理的結(jié)果繼續(xù)遍歷
// array.reduce([callback],[initialValue])
var arr = [10, 20, 30, 40];
var res = arr.reduce(function (result, item, index) {
// [initialValue] 初始值不傳遞,result默認(rèn)的是數(shù)組第一項(xiàng)欺嗤,然后reduce從數(shù)組第二項(xiàng)開始遍歷
// 每遍歷一次 回調(diào)函數(shù)被觸發(fā)執(zhí)行一次
// + result 存儲(chǔ)的是上一次回調(diào)函數(shù)返回的結(jié)果(除了第一次初始值或者數(shù)組第一項(xiàng))
// + item 當(dāng)前遍歷的一項(xiàng)
// + index 當(dāng)前遍歷一項(xiàng)的索引
return item + result;
});
var res2 = arr.reduce((result, item) => {
// 如果傳遞了初始值参萄,則result第一次的結(jié)果就是初始值,item從數(shù)組第一項(xiàng)開始遍歷
return item + result;
}, 0);
模擬實(shí)現(xiàn) reduce
Array.prototype.reduceTest = function reduceTest(callback, initial) {
var self = this; // this =>arr
var i = 0;
// callback 必須是函數(shù)
if (typeof callback !== "function")
throw new TypeError("callback must be an function");
// 判斷是否有初始值
if (typeof initial === "undefined") {
// 如果沒(méi)有初始值 initial 初始值為 數(shù)組 的第一項(xiàng)煎饼,然后從數(shù)組第二項(xiàng)開始遍歷
initial = self[0];
i = 1;
}
for (; i < self.length; i++) {
var item = self[i];
index = i;
initial = callback(initial, item, index);
}
return initial;
};
用柯里化的思想和 reduce 實(shí)戰(zhàn)一道題目
求和;
var sum = curring(10);
console.log(sum(20));
console.log(sum(20, 30));
function curring(x) {
// 利用閉包機(jī)制存儲(chǔ)x
return function (...args) {
args.unshift(x);
return args.reduce((result, item) => {
return result + item;
});
};
}
組合函數(shù)
組合函數(shù)是函數(shù)式編程的重要概念讹挎,處理數(shù)據(jù)的函數(shù)就像是管道一樣連接起來(lái),然后數(shù)據(jù)穿過(guò)管道最終得到結(jié)果
const add1 = (x) => x + 1;
const add2 = (x) => x * 3;
const add3 = (x) => x / 2;
// 然后我們構(gòu)建一個(gè)組合函數(shù)
const operat = compose(add1, add2, add3);
operat(0); // 相當(dāng)于 add3(add2(add1(0)))
// 那么這個(gè)compose函數(shù)怎么編寫呢吆玖?
function compose(...funs) {
return function operat(x) {
if (funs.length === 0) return x;
if (funs.length === 1) return funs[0](x);
// reduce 數(shù)組 從左向右執(zhí)行 reduceRight 數(shù)組從右向左執(zhí)行
return funs.reduceRight(function (result, item) {
if (typeof item !== "function") return result;
return item(result);
}, x);
};
}
var operate = compose(div2, mul3, add1);
var result = operate(0);
console.log(result);
// funs :存儲(chǔ)需要指向函數(shù)的順序 最后面的函數(shù)優(yōu)先執(zhí)行
// 執(zhí)行compose 只是把要執(zhí)行的函數(shù)存儲(chǔ)起來(lái)筒溃,還沒(méi)有執(zhí)行
// 返回一個(gè)operat 處理函數(shù),執(zhí)行函數(shù)沾乘,并且傳遞初始值怜奖,才按照之前存儲(chǔ)的順序依次執(zhí)行
// 依舊是用到了閉包的思想
模擬實(shí)現(xiàn)函數(shù)柯里化
function curry(func) {
return function curried(...args) {
// 判斷實(shí)參和形參的個(gè)數(shù) 如果參數(shù)大于或者等于,那個(gè)直接執(zhí)行下面的返回函數(shù)把參數(shù)傳進(jìn)去
// 否則進(jìn)入判斷意鲸,把參數(shù)合并再傳入函數(shù)中烦周,
if (args.length < func.length) {
return function () {
return curried(...args.concat(Array.from(arguments)));
};
}
return func(...args);
};
}
function getSum(a, b, c) {
return a + b + c;
}
const curried = curry(getSum);
console.log(curried(1, 2, 3));
console.log(curried(1)(2, 3));
命令式編程和函數(shù)式編程的區(qū)別
命令式編程:自己編寫代碼,管控步驟和邏輯(自己可以靈活掌握步驟)
函數(shù)式編程:具體的實(shí)現(xiàn)步驟已經(jīng)被封裝成方法怎顾,我們只需要調(diào)用方法獲取結(jié)果即可读慎,無(wú)需關(guān)注怎么實(shí)現(xiàn)的。
弊端:無(wú)法靈活掌握?qǐng)?zhí)行的步驟