柯里化定義
維基百科定義
- 是把接收多個(gè)參數(shù)的函數(shù),變成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù)焕盟,并且返回接受余下的參數(shù),而且返回結(jié)果的新函數(shù)的技術(shù)
- 柯里化聲稱 “如果你固定某些參數(shù)宏粤,你將得到接受余下參數(shù)的一個(gè)函數(shù)”
簡(jiǎn)單講就是將函數(shù)的多個(gè)參數(shù)返回不同的函數(shù)執(zhí)行脚翘,將多個(gè)參數(shù)進(jìn)行執(zhí)行拆解成單步驟執(zhí)行,一個(gè)函數(shù)執(zhí)行一個(gè)步驟
更簡(jiǎn)單的講只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它绍哎,讓它返回一個(gè)函數(shù)去處理剩余的參數(shù)
舉個(gè)例子
function foo(a, b, c) {
return a + b + c;
}
//柯里化處理之后的函數(shù)
function sum(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
console.log(foo(10, 20, 30));
console.log(sum(10)(20)(30));
foo函數(shù)接收三個(gè)函數(shù)来农,利用柯里化將三個(gè)參數(shù)返回相對(duì)應(yīng)的函數(shù)去執(zhí)行,每個(gè)函數(shù)執(zhí)行一個(gè)對(duì)參數(shù)的操作
可以將上面的柯里化處理函數(shù)簡(jiǎn)化
const sum = (a) => (b) => (c) => a + b + c;
但是在將上面的例子來(lái)看崇堰,進(jìn)行柯里化之后的函數(shù)沃于,步驟繁瑣,執(zhí)行效率也不高海诲,但是為什么還要將函數(shù)進(jìn)行柯里化呢繁莹,這里就涉及到設(shè)計(jì)模式相關(guān)的,有一個(gè)重要的模式就是讓函數(shù)的職責(zé)單一
- 當(dāng)我們?cè)谶M(jìn)行函數(shù)式編程特幔,每一個(gè)函數(shù)都盡可能只處理一類(lèi)或者一個(gè)問(wèn)題咨演,而不是將所有的問(wèn)題交給一個(gè)函數(shù)進(jìn)行處理
- 那么我們是否就可以將每次傳入的參數(shù)在單一的函數(shù)中進(jìn)行處理,處理完后在下一個(gè)函數(shù)中再使用處理后的結(jié)果
function sum(a) {
a = a + 2
return function (b) {
b = b * 2
return function (c) {
c = c ** 2
return a + b + c;
};
};
}
柯里化還有一個(gè)重要的使用場(chǎng)景是對(duì)參數(shù)復(fù)用
function log(date, type, message) {
console.log(
`[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`
);
}
log(new Date(), 'debug', '參數(shù)錯(cuò)誤');
log(new Date(), 'debug', 'not a function');
log(new Date(), 'debug', 'bad request');
以上面的例子來(lái)說(shuō)蚯斯,前兩個(gè)參數(shù)是重復(fù)的薄风,每次都要寫(xiě)同樣的代碼,唯一不同的是后面的message不同拍嵌,如果有大量的日志需要重寫(xiě)遭赂,會(huì)非常麻煩,這時(shí)就可以用柯里化將參數(shù)復(fù)用
const log = (date) => (type) => (message) => {
console.log(
`[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`
);
};
//時(shí)間重復(fù)
const datelog = log(new Date());
datelog('debug')('參數(shù)錯(cuò)誤');
datelog('request')('bad request');
//時(shí)間和類(lèi)型重復(fù)
const dataAndType = log(new Date())('debug');
dataAndType('參數(shù)錯(cuò)誤');
dataAndType('not a function');
dataAndType('bad request');
通過(guò)柯里化可以將重復(fù)的參數(shù)進(jìn)行復(fù)用撰茎,減少了代碼的冗余
自動(dòng)柯里化函數(shù)實(shí)現(xiàn)
上面的柯里化函數(shù)都是手動(dòng)實(shí)現(xiàn)的嵌牺,接下來(lái)用一個(gè)函數(shù)來(lái)自動(dòng)實(shí)現(xiàn)柯里化的過(guò)程
function currying(fn) {
//傳入需要處理的函數(shù)
function curryied(...args) {
//傳入處理函數(shù)的參數(shù)
/**
* 1.fn(10,20,30)
* 2.fn(10)(20)(30)
* 3.fn(10,20)(30)
*/
//第一種情況
//函數(shù)調(diào)用時(shí)參數(shù)全部使用
if (args.length >= fn.length) {
return fn.apply(this, args); //直接返回當(dāng)前調(diào)用的函數(shù),并且綁定當(dāng)前調(diào)用函數(shù)的this
} else {
//第二種情況
//第二種情況和第三種情況是一樣的,這里是將第二種情況轉(zhuǎn)換為第三種情況,在轉(zhuǎn)換為第一種情況
//遞歸調(diào)用
//此時(shí)args是10,args2是20,
//現(xiàn)在是需要將傳遞過(guò)來(lái)的參數(shù)進(jìn)行拼接,直到轉(zhuǎn)變成第一種情況
function curryied2(...args2) {
return curryied.apply(this, [...args, ...args2]);
}
return curryied2;
}
}
return curryied;
}
function add(x, y, z) {
return x + y + z;
}
var curryadd = currying(add);
console.log(curryadd);
console.log(curryadd(10)(20)(30));
console.log(curryadd(10, 20, 30));
console.log(curryadd(10, 20)(30));