函数柯里化currying的概念最早由俄国数学家Moses Schönfinkel发明,而后由著名的数理逻辑学家Haskell Curry将其丰富和发展,currying由此得名。本文将详细介绍函数柯里化(curring)
定义:
柯里化,可以理解为提前接收部分参数,延迟执行,不立即输出结果,而是返回一个接受剩余参数的函数。因为这样的特性,也被称为部分计算函数。柯里化,是一个逐步接收参数的过程。在接下来的剖析中,你会深刻体会到这一点。
反柯里化,是一个泛型化的过程。它使得被反柯里化的函数,可以接收更多参数。目的是创建一个更普适性的函数,可以被不同的对象使用。
一、柯里化
刚开始接触到柯里化概念是判断一个变量类型的时候
function checkType(type) {
return function(content) {
return Object.prototype.toString.call(content) === `[object ${type}]`;
}
}
let isString = checkType("String");
console.log(isString("sad")); // true
封装一个检测变量类型的函数 checkType,当我们调用 checkType 的时候在返回一个函数,这个函数可以拿到 type 参数,空间不会被释放,柯里化的函数,通用性会降低,函数的功能会更具体
通用的柯里化函数:
// 通用柯里化函数
function curring(fn,arr =[]){
let len = fn.length; // 代表fn需要传入参数的个数
return function(...args){
arr = [...arr, ...args];
if(arr.length < len ){
// 传入的参数达不到执行条件,递归继续接受参数
return curring(fn,arr);
}else{
// console.log('111');
return fn(...arr);
}
}
}
下面我们用通用的柯里化函数,封装一个判断一个变量类型的函数
// 验证函数
function checkType(type,value){
return Object.prototype.toString.call(value) === `[object ${type}]`;
}
// 通用柯里化函数
function curring(fn,arr =[]){
// console.log(arr);
let len = fn.length; // 代表fn需要传入参数的个数
return function(...args){
arr = [...arr, ...args];
// console.log(arr);
if(arr.length < len ){
// 传入的参数达不到执行条件,递归继续接受参数
return curring(fn,arr);
}else{
// console.log('111');
return fn(...arr);
}
}
}
// 生成验证函数
let util = {};
let types = ['String', 'Number', 'Boolean', 'Null', 'Undefined'];
types.forEach(type => {
util[`is${type}`] = curring(checkType)(type);
})
console.log(util.isString('hello'))
二、反柯里化
- 非我之物,为我所用
- 增加被反柯里化方法接收的参数
// 轻提示
function Toast(option){
this.prompt = '';
}
Toast.prototype = {
constructor: Toast,
// 输出提示
show: function(){
console.log(this.prompt);
}
};
// 新对象
var obj = {
prompt: '新对象'
};
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); // 输出"新对象"
在上面的例子中,Toast.prototype.show
方法,本来是 Toast
类的私有方法。跟新对象 obj
没有半毛钱关系。
经过反柯里化后,却可以为 obj
对象所用。
为什么能被 obj
所用,是因为内部将 Toast.prototype.show
的上下文重新定义为 obj
。也就是用 apply
改变了this指向。
而实现这一步骤的过程,就需要增加反柯里化后的 objShow
方法参数。