在函数式编程中柯里化是一个十分重要的概念

那么 什么是柯里化呢?

定义:

只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数。这个过程就叫做柯里化。

实例:

// 未柯里化的函数
function add1(x,y,z){
	return x+y+z
}
console.log(add1(10,20,30))

// 柯里化处理的函数
function add2(x){
	return function(y){
		return function(z){
			return x+y+z
		}
	}
}
// 可以化处理的函数可以简化成
// var sum2 = x=>y=>z=>x+y+z
console.log(add2(10)(20)(30))

光从上面的例子来看的话,就会觉得函数的柯里化没有必要,
反而更加复杂化了,但其实不是这样。

在函数式编程中,我们往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程都交给一个函数来处理。

那么我们就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果。

比如我们那上面的案例进行一个修改:传入的函数分别需要进行如下的处理

  • 第一个参数+2
  • 第二个参数*2
  • 第三个参数**2
function addx(x){
	x=x+2
	return function(y){
		y=y*2
		return function(z){
			z=z**2
			return x+y+z
		}
	}
}

另外一个使用柯里化的场景是可以帮助我们实现复用参数逻辑

makeAdder函数要求我们传入一个num(当我们需要的时候,可以对num进行一些修改)

function makeAdder(num){
	return function(count){
		return num+count
	}
}

var add5 = makeAdder(5)
add5(10)
add5(100)

var add10 = makeAdder(10)
add10(10)
add10(100)

在这里我们演示一个案例 需求是打印一些日志
(包括时间,类型,信息)

// 普通函数的实现方式
function log(date, type, message) {
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}

// log(new Date(), "DEBUG", "查找到轮播图的bug")
// log(new Date(), "DEBUG", "查询菜单的bug")
// log(new Date(), "DEBUG", "查询数据的bug")

// 柯里化的优化
var log = date => type => message => {
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}

// 如果我现在打印的都是当前时间
var nowLog = log(new Date())
nowLog("DEBUG")("查找到轮播图的bug")
nowLog("FETURE")("新增了添加用户的功能")

var nowAndDebugLog = log(new Date())("DEBUG")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")


var nowAndFetureLog = log(new Date())("FETURE")
nowAndFetureLog("添加新功能~")

相信通过上面的总结 大家应该对函数的柯里化的重要性有了一定的认识

那么现在我们在提一个新的需求——我们现在需要一个函数,这个函数能够将我们传入的函数自动生成柯里化函数,不需要我们自己再写一个新的函数

// 柯里化函数的实现
function newCurry(fn){
	function curried(...args){
		// 判断当前已经接收的参数的个数,与参数fn本身需要接受的参数是否一致
		// 当已经传入的参数 大于等于 需要的参数的时候,就执行函数
		if(args.length >= fn.length){
			return fn.call(this,...args)
		}else{
			// 当已经传入的参数没有达到fn的参数个数的时候,需要返回一个函数继续来接收参数
			return curried2(...args2){
				// 接收完参数后,需要递归调用curried来检查个数是否已经一致了
				return curried.call(this,args.concat(args2))
			}
		}
	}
	return curried
}

理解组合函数

组合函数是在js开发过程中的一种对函数的技巧、模式

比如我们现在需要对某一个数据进行函数的调用,执行两个函数fn1和fn2,这两个函数是依次执行的
如果我们每一次都需要对两个函数进行调用,操作上就会显得重复
所以我们可以将两个函数组合起来,自动依次调用
这个过程就是对函数的组合,我们称为组合函数

function double(num){
	return num*2
}

function square(num){
	return num**2
}

function compose(fn1,fn2){
	return function(x){
		return fn2(fn1(x))
	}
}

var calcFn = compose(double,square)
console.log(calcFn(10))