函數(shù)柯里化currying的概念最早由俄國(guó)數(shù)學(xué)家Moses Sch?nfinkel發(fā)明前酿,而后由著名的數(shù)理邏輯學(xué)家Haskell Curry將其豐富和發(fā)展滞造,currying由此得名。本文將詳細(xì)介紹函數(shù)柯里化(curring)
定義:
柯里化茄蚯,可以理解為提前接收部分參數(shù)算吩,延遲執(zhí)行哥桥,不立即輸出結(jié)果,而是返回一個(gè)接受剩余參數(shù)的函數(shù)狸捅。因?yàn)檫@樣的特性衷蜓,也被稱(chēng)為部分計(jì)算函數(shù)〕竞龋柯里化磁浇,是一個(gè)逐步接收參數(shù)的過(guò)程。在接下來(lái)的剖析中瞧省,你會(huì)深刻體會(huì)到這一點(diǎn)扯夭。
反柯里化,是一個(gè)泛型化的過(guò)程鞍匾。它使得被反柯里化的函數(shù),可以接收更多參數(shù)骑科。目的是創(chuàng)建一個(gè)更普適性的函數(shù)橡淑,可以被不同的對(duì)象使用。
一咆爽、柯里化
剛開(kāi)始接觸到柯里化概念是判斷一個(gè)變量類(lèi)型的時(shí)候
function checkType(type) {
return function(content) {
return Object.prototype.toString.call(content) === `[object ${type}]`;
}
}
let isString = checkType("String");
console.log(isString("sad")); // true
封裝一個(gè)檢測(cè)變量類(lèi)型的函數(shù) checkType梁棠,當(dāng)我們調(diào)用 checkType 的時(shí)候在返回一個(gè)函數(shù),這個(gè)函數(shù)可以拿到 type 參數(shù)斗埂,空間不會(huì)被釋放符糊,柯里化的函數(shù),通用性會(huì)降低呛凶,函數(shù)的功能會(huì)更具體
通用的柯里化函數(shù):
// 通用柯里化函數(shù)
function curring(fn,arr =[]){
let len = fn.length; // 代表fn需要傳入?yún)?shù)的個(gè)數(shù)
return function(...args){
arr = [...arr, ...args];
if(arr.length < len ){
// 傳入的參數(shù)達(dá)不到執(zhí)行條件,遞歸繼續(xù)接受參數(shù)
return curring(fn,arr);
}else{
// console.log('111');
return fn(...arr);
}
}
}
下面我們用通用的柯里化函數(shù)男娄,封裝一個(gè)判斷一個(gè)變量類(lèi)型的函數(shù)
// 驗(yàn)證函數(shù)
function checkType(type,value){
return Object.prototype.toString.call(value) === `[object ${type}]`;
}
// 通用柯里化函數(shù)
function curring(fn,arr =[]){
// console.log(arr);
let len = fn.length; // 代表fn需要傳入?yún)?shù)的個(gè)數(shù)
return function(...args){
arr = [...arr, ...args];
// console.log(arr);
if(arr.length < len ){
// 傳入的參數(shù)達(dá)不到執(zhí)行條件,遞歸繼續(xù)接受參數(shù)
return curring(fn,arr);
}else{
// console.log('111');
return fn(...arr);
}
}
}
// 生成驗(yàn)證函數(shù)
let util = {};
let types = ['String', 'Number', 'Boolean', 'Null', 'Undefined'];
types.forEach(type => {
util[`is${type}`] = curring(checkType)(type);
})
console.log(util.isString('hello'))
二、反柯里化
- 非我之物漾稀,為我所用
- 增加被反柯里化方法接收的參數(shù)
// 輕提示
function Toast(option){
this.prompt = '';
}
Toast.prototype = {
constructor: Toast,
// 輸出提示
show: function(){
console.log(this.prompt);
}
};
// 新對(duì)象
var obj = {
prompt: '新對(duì)象'
};
function unCurrying(fn){
return function(){
var args = [].slice.call(arguments);
console.log(args);
var that = args.shift();
return fn.apply(that);
}
}
var objShow = unCurrying(Toast.prototype.show);
objShow(obj); // 輸出"新對(duì)象"
在上面的例子中模闲,Toast.prototype.show
方法,本來(lái)是 Toast
類(lèi)的私有方法崭捍。跟新對(duì)象 obj
沒(méi)有半毛錢(qián)關(guān)系尸折。
經(jīng)過(guò)反柯里化后,卻可以為 obj
對(duì)象所用殷蛇。
為什么能被 obj
所用实夹,是因?yàn)閮?nèi)部將 Toast.prototype.show
的上下文重新定義為 obj
。也就是用 apply
改變了this指向粒梦。
而實(shí)現(xiàn)這一步驟的過(guò)程亮航,就需要增加反柯里化后的 objShow
方法參數(shù)。