函数柯里化与反柯里化

前言

在函数式编程中经常会遇到很多概念,比如纯函数、柯里化、高阶函数。

  • 纯函数
    一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用
  • 柯里化
    接受多个参数的函数转换成接受单一参数的函数的操作
  • 高阶函数
    一个可以接收函数作为参数,并且返回一个函数的函数

函数柯里化

函数柯里化又称部分求值,函数首先会接收一些参数,之后该函数并不会立即求值,而是继续返回另外一个函数,上一个函数以闭包的形式保存,待到函数被真正需要求值的时候,将之前传入的所有参数拿来一次性求值。就好像我们计算每个月的开销,并不会每消费一笔就计算总值,而是等到月底再把全部消费加起来计算总值。

通用的柯里化函数如下:

function currying(fn) {
    var slice = Array.prototype.slice,
    __args = slice.call(arguments, 1);
    return function () {
        var __inargs = slice.call(arguments);
        return fn.apply(null, __args.concat(__inargs));
   };
 }

举个栗子
对于add函数,实现任意每次任意输入几个参数,得到参数值的累加结果

function add(...rest) {
    var args = [];
    args.push(...rest);
    return function cb(...rest) {
        if(rest.length == 0){
            return args.reduce(function(acc, cur) {
                return acc + cur;
            }); 
        }else{
            args.push(...rest);
            return cb;
        }
    }
}

console.log(add(1,4,5)(7,8)())  //25

应用场景

  • 提高适用性
    比如对于反复输入相同参数的函数,通过柯里化,只需传入不同的参数
  • 延迟执行
    如上面的add函数,一直等到不再传入参数时执行累加
  • 固定易变因素
    如bind函数的实现,具体可参考我的模拟bind函数实现

反柯里化

通俗来说, 使用uncurrying技术, 可以让任何对象拥有原生对象的方法。比如:

var obj = {}
var push = Array.prototype.push.uncurrying();
push(obj, 'first');
console.log(obj[0]);// first

由于在javascript里面,很多函数都不做对象的类型检测,而是只关心这些对象能做什么,也就是常说的鸭子类型。所以我们需要解决的只剩下一个问题, 如何通过一种通用的方式来使得一个对象可以冒充array对象。
反柯里化的实现代码非常简单,只有如下几行:

Function.prototype.uncurrying = function() {
    var _this = this;
    return function() {
        return Function.prototype.call.apply(_this, arguments);
    }
}

我们以上面那个给obj赋予push函数为例,分析反柯里化函数调用时的具体操作。

Function.prototype.uncurrying = function() {
    var _this = this;  //Array.prototype.push作为this赋值给_this
    return function() {
        /* 使_this具有函数的call方法,并执行该call方法,即执行Array.prototype.push.call。
           由于apply以数组形式接收参数,arguments是[obj,'first']
           call函数接收参数第一个为执行上下文,后面为以逗号形式的参数列表,所以obj作为call函数的上下文,参数是first
           最后相当于执行了 Array.prototype.push.call(obj, 'first')*/
        return Function.prototype.call.apply(_this, arguments);
    }
}

你可能感兴趣的:(函数柯里化与反柯里化)