美文网首页
JS函数式编程之柯里化

JS函数式编程之柯里化

作者: treeQQ | 来源:发表于2019-07-22 14:18 被阅读0次

    JS函数式编程之柯里化

    为什么要了解柯里化

    柯里化是函数式编程必须要使用的. 这里我们就先介绍下什么是柯里化, 然后通过一个小例子体会柯里化的特点和使用方式.

    什么是柯里化

    curry 的概念很简单:只传递给函数一部分参数来调用它,让它返回一个函数去处
    理剩下的参数。
    你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。

    [引自: js函数式编程指南]

    小例子——两个数字相加函数的柯里化

    // 非柯里化方式实现两个数相加的函数
    function add(x, y) {
        return x + y;
    }
    // 调用方式
    var result = add(1, 2); // => 3
    
    // 柯里化上面的求和函数, 即将两个参数的add函数改成传一个参数的函数
    function curryAdd(x) {    
        return function(y) {
            return x + y;
        }
    }
    // 调用方式
    var result = curryAdd(1)(2); // => 3
    

    我们看到非柯里化方式实现的函数调用时,需要传递两个参数, 但是柯里化后, 传递第一个参数返回了一个函数, 返回的函数, 参数是之前的函数的第二个参数. 这样就保证了每个函数调用都传递一个参数.

    既然结果一样, 柯里化后有什么好处呢?

    如果我们有这样一个需求, 那柯里化就会派上用场. 我需要计算每个人的工资, 工资由基本工资和绩效工资组成. 每个人的基本工资一样, 但是他们的绩效工资不一样.用非柯里化的函数计算如下

    // 假设基本工资是5000
    // 员工a 绩效工资2000
    var salaryA = add(5000, 2000);
    // 员工b 绩效工资3000
    var salaryB = add(5000, 3000);
    

    用柯里化后的函数计算如下

    // 创建一个缓存了基本工资的相加计算函数
    var curryAddedX = curryAdd(5000);
    // 计算员工a的工资
    var salaryA = curryAddeX(2000);
    // 计算员工b的工资
    var salaryB = curryAddedY(3000);
    

    用了柯里化后的函数计算, 就可以避免每次都传递5000这个基本工资了. 好处就是

    1. 减少了代码量
    2. 不用担心本该固定的值手误写错(在这里就是基本工资的值)

    小例子——利用已有函数筛选数组中满足条件的元素

    已有一个函数

    // 第一个参数, 是否包含的字符串, 第二个参数是被检测的字符串
    function isContain(smallStr, str) {
        return str.indexOf(smallStr) !== -1;
    }        
    

    使用数组的filter方法, 与上面的函数配合, 筛选出包含指定字符串的字符串

    var arr = ['dog', 'cat', 'how are you'];
    // 将isContain函数柯里化
    function curryIsContain(smallStr) {
        return function(str) {
            return str.indexOf(smallStr) !== -1;
        }
    }
    // 创建一个缓存了参数smallStr的筛选的函数, 用于筛选出含有空格的元素
    var containSpace= curryIsContain(' ');
    var result = arr.filter(containSpace);
    // 创建一个用于筛选含有o的字符串
    var containO = curryIsContain('o');
    result = arr.filter(containO);                              
    

    我们发现我们这里从新写了一个curryIsContain方法.

    其实是用通用的办法把isContain转换成curryIsContain的.

    这个办法就是: 柯里化函数. 我们来实现下他

    // fn参数为将要被柯里化的函数, srcArgs参数为之前缓存的参数
    function curry(fn, srcArgs) {
        return function() {
            var args = [].slice.apply(arguments);
            var fullArgs = srcArgs === undefined ? args : srcArgs.concat(args);
            if(fullArgs.length >= fn.length) {
                return fn.apply(null, fullArgs);
            } else {
                return curry(fn, fullArgs);
            }
        }
    }
    

    我们用我们这个柯里化函数把isContain转换为curryIsContain

    // 通过curry转换的curryIsContain具有同样的使用方式
    var curryIsContain = curry(isContain);
    

    提供柯里化的开源框架

    ramda

    lodash

    总结

    柯里化的函数, 拥有暂存部分参数, 延迟执行的能力. 直至所有的参数都提供完才执行有效功能代码.

    如果我们刚好有个可用的多参函数FucntionMutiParams.

    恰好另外一个地方, 需要使用函数FucntionMutiParams.

    但是部分参数已经固定不需要改, 比如第一个例子中的固定工资.

    或者有的地方只需要一个参数的函数. 事实上函数式编程的另外一个操作组合函数, 就需要只有一个参数的函数.

    后面我们学习组合函数, 就会理解柯里化的必要性.

    相关文章

      网友评论

          本文标题:JS函数式编程之柯里化

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