美文网首页
一起学习柯里化

一起学习柯里化

作者: isSunny | 来源:发表于2019-07-26 17:37 被阅读0次

    柯里化,第一次听这个词的时候一脸懵逼,百度上看了一些大佬的文章,在这里和大家一起学习一下什么是柯里化。

    官方解释:柯里化,英文currying,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    说的还是很难懂啊,直接上个简单🌰吧,就能明白了,拿我们最常见的add函数

    //正常add(x,y)函数
    function add(x,y){
        return x+y;
    }
    //柯里化后的函数
    function curryAdd(x){
        return function(y){
            return x+y;
        }
    }
    console.log(add(1,2));//3
    console.log(curryAdd(1)(2));//3
    

    从上面例题我们可以看出来,就是函数把参数变成了先用一个函数接收部分参数,然后返回一个函数去处理剩余的参数。

    直接敲代码吧,奉上封装好的通用方法

    1.简单版
    function curry(fn){
        var args =Array.prototype.slice.call(arguments,1);
        return function(){
            var _args = Array.prototype.slice.call(arguments);//新的参数
            var newArgs = args.concat(_args);
            return fn.apply(this,newArgs);//apply不要忘记哦~~
        }
    }
    function add(a, b) {
        return a + b;
    }
    
    var f1 = curry(add,1,2);
    console.log(f1()); //3
    var f2 = curry(add,1);
    console.log(f2(2)); //3
    var f3 = curry(add);
    console.log(f3(1, 2)) // 3
    

    emm,这一般是简单版,不能链式调用,也就是如f3(1)(2);
    废话不多说,直接上加强版

    2.加强版
    function curry(fn){
        var args = Array.prototype.slice.call(arguments,1);
        var len = fn.length;//参数长度
        return function(){
            var _args = Array.prototype.slice.call(arguments);//新的参数
            var newArgs = args.concat(_args);//将所有参数集合在一起
            if(newArgs.length<len){
                //判断当前函数的参数和期望函数参数
                return curry.call(this,fn,...newArgs);//如果不够,递归调用
            }else{
                return fn.apply(this,newArgs);;//如果够,执行函数
            }
        }
    }
    function add(x,y){
        return x+y;
    }
    var f1 = curry(add)
    console.log(f1(2)(1));//3
    var f2 = curry(add,1);
    console.log(f2(2));//3
    var f3 = curry(add,1,2);
    console.log(f3());//3
    
    柯里化有什么好处呢?

    柯里化有三个常见的作用:
    详细可以参考这一篇文章JS中的柯里化(currying

    1. 参数复用;
    2. 提前返回;
    3. 延迟计算/运行。
    bind实现柯里化:

    具体可以看我写过的这篇文章bind的运用和bind的实现

    最后跟我一起看一道经典的curry面试题

    实现一个add方法,使计算结果能够满足如下预期:
    add(1)(2)(3) = 6;
    add(1, 2, 3)(4) = 10;
    add(1)(2)(3)(4)(5) = 15;

    上面写的通用版,只针对有特定参数个数的函数适用,所以这道题还要重新思考一下。
    由于这道题传入的参数个数不固定,这里就需要使用函数的toString来完成。

    • 法一:
    function add(){
        var args = Array.prototype.slice.call(arguments);
        var fn = function(){
            //直接利用闭包的特性保存args并收集所有的参数值
             args.push(...arguments);//es6写法,
             return  add(...args);//es6写法
            // es5写法 add.apply(null,args);
            //也可以直接返回fn
            //return fn;        
        }
     // 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
        fn.toString = function(){
            return args.reduce(function(a,b){
                return a+b;
            })
        }
        return fn;
    }
    console.log(add(1)(2)(3) );//6
    console.log(add(1, 2, 3)(4)); //10
    console.log(add(1)(2)(3)(4)(5));//15
    
    • 法二:
    function add(){
        var args = Array.prototype.slice.call(arguments);
        var fn = function(){
            var _args = Array.prototype.slice.call(arguments);
            var newArgs = args.concat(_args);//参数拼接
            return  add.apply(null,newArgs);//es5写法
            // es6写法 add(...newArgs);
        }
        fn.toString = function(){
            return args.reduce(function(a,b){
                return a+b;
            })
        }
        return fn;
    
    }
    
    console.log(add(1)(2)(3) );//6
    console.log(add(1, 2, 3)(4)); //10
    console.log(add(1)(2)(3)(4)(5));//15
    
    

    其实方法一和方法二都是一样的,只不过是有一些es5和es6上写法差别,就分开写了。

    这里说一下为啥需要使用函数的toString
    当我们执行函数,直接参与计算的时候,会隐式调用toString,直接将函数体转换为字符串参与计算。

    function a(){return 10};
    console.log(a+20);//function a(){return 10}20
    

    但是如果我们重写toString方法,函数参与计算时候,就可以输出我们想要的结果了。

    function a(){return 10};
    a.toString = function(){
        return 20;
    }
    console.log(a+20);//40
    

    现在应该是可以理解了吧~~~就不多说了。

    相关文章

      网友评论

          本文标题:一起学习柯里化

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