柯里化和反柯里化
2018-09-01 本文已影响0人
灯光树影
一、柯里化
- 定义
函数柯里化就是把一个函数中的一些可以固定的参数固定后生成新的函数
比如一个函数:
/**
牛顿第二定律
@param m {number} 物体质量
@param a {number} 加速度
*/
function F(m, a){
return m * a;
}
现在有一个需求:就是物体的质量不变,但是它的加速度时刻改变,如果需要计算它某些时刻所受的力,那么就需要不断的调用F。
就像这样:
F(m, a0); // 0时刻
F(m, a1); // 1时刻
F(m, a2); // 2时刻
可是,我们需要的质量是固定的,为什么不把函数的m固定,下一次调用只需要传入a的值就可以了。这时,我们希望函数调用变成这样:
F1(a0); // 0时刻
F1(a1); // 1时刻
F1(a2); // 2时刻
这样,把部分参数固定的需求,生成一个新的函数(这里是F1)的过程就是函数柯里化。
- 通用实现
/**
函数柯里化
@param func {function} 需要柯里化的函数(原函数)
@return {function} 柯里化后的函数
*/
function currying(func){
// 固定参数
var slice = Array.prototype.slice;
var args = slice.call(arguments, 1);
/**
--> slice.call(arguments, 1)
--> arguments.slice(1);
*/
// 返回新的函数
return function(){
// 获取新的函数调用时的参数
var inArgs = slice.call(arguments);
// 把固定好的参数与inArgs拼接起来,调用原函数
return func.apply(null, args.concat(inArgs));
}
}
原理: 使用闭包保存需要固定的参数,返回一个“自动”将固定的参数值传递给原函数的新函数。
- 柯里化函数的使用
// 沿用上面的例子,生成F1函数
var m = 20; // 假设m等于20
var F1 = currying(F, m);
// 调用:
F1(a0);
F2(a1);
...
总结: 函数柯里化的目的就是把通用函数的适用范围缩小,使其专用性更强。
二、反柯里化
- 定义
柯里化是反柯里化的逆过程。反柯里化就是把函数的适用范围扩大,削弱其专用性。
例子:
有两个对象mouse和cat,它们的定义是:
var cat = {
name: 'Tom',
getName: function(){
return this.name;
}
}
var mouse = {
name: 'Jerry'
}
我们知道,输出cat的名字,使用cat.getName();只是这样,getName专用于cat对象,为了将它用于其它对象,比如mouse我希望得到一个这样的函数调用形式:
// obj是需要输出名字的对象
commonGetName(obj);
这个函数的内部应该实现类似这样的调用形式:
obj.getName();
这样,增加了不固定的参数,扩大了使用范围,就是函数反柯里化
- 通用实现
/**
函数反柯里化
@return {function} 处理后的函数
*/
function uncurring(){
var that = this;
return function(){
return Function.prototype.call.apply(that, arguments);
/**
--> apply具有分解参数的作用,这很重要。
apply把arguments分解成了args1, args2, ...
--> that.call(args1, args2, args3, ...);
--> args1.that(args2, args3, ...);
*/
}
}
- 使用
这是使用反柯里化实现一个适用于cat和mouse的获取名字的方法
commonGetName = cat.getName.uncurring();
commonGetName(cat); // 输出猫的名字
commonGetName(mouse); // 输出鼠的名字
参考文章:
https://www.cnblogs.com/pigtail/p/3447660.html
https://www.imooc.com/article/46624