美文网首页
函数柯里化与反柯里化

函数柯里化与反柯里化

作者: _章鱼小丸子 | 来源:发表于2019-06-24 15:37 被阅读0次

    前言

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

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

    函数柯里化

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

    通用的柯里化函数如下:

    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);
        }
    }
    

    相关文章

      网友评论

          本文标题:函数柯里化与反柯里化

          本文链接:https://www.haomeiwen.com/subject/rzznqctx.html