函数柯里化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 方法参数。

参考文档: