JS每日一题:函数式编程中柯里化如何理解?
发布于 5天前 作者 ab8512 190 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

20190314期

函数式编程中柯里化如何理解?

定义: 柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术

好像有点绕口,我们用代码来消化一下

const add = function(x) {
  return function(y) {
    return x + y;
  };
};

const increment = add(1); // 第一个参数
increment(2); // 第二个参数
// 3

const addTen = add(10); // 第一个参数
addTen(2); // 第二个参数
// 12

看了上面的代码是不是清淅多了, 不过看上去好像没什么意义? 下面我们转变一下,写几个实际工作中能用上的例子

// 引入lodash的curry实现
const curry = require('lodash').curry;

const match = curry(function(what, str) {
  return str.match(what);
})

// 这样子看是不是就感受到柯里化的美妙了 ?
match(/\s+/g, "hello world") // [ ' ' ]

什么,还是没什么意思? 我们再来看一组示例

const person = [{name: 'JS'}, {name: '每日一题'}]
const name = person.map( (item) => item.name) // JS每日一题

// 下面我们用curry在实现

const name = person.map(prop('name')) // JS每日一题 prop为自实现复用的函数, 这样我们的代码会更易维护易懂, curry的实现我们直接能把这一句person.map(prop('name')) 翻译成person 对象遍历(map)获取(prop) name 属性

好了, 好像有点感觉了, 但大家注意到上面是引的lodash的curry函数,我们自己如何实现一个curry函数呢?

实现curry

先来梳理一下curry的性点

  • 延迟执行(就是bind函数的那个延迟)
  • 参数复用

好了,我们基于这两个特性模拟实现一个最简化的curry

function curry(fn, args) {
    var length = fn.length;
    args = args || [];
    return function() {
        var _args = args.slice(0),
            arg, i;
        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            _args.push(arg);
        }
        // 对参数形式不同分别处理
        if (_args.length < length) {
            return curry.call(this, fn, _args);
        }
        else {
            return fn.apply(this, _args);
        }
    }
}


var fn = curry(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]

总结

  • 固定不变的参数,实现参数复用是 curry 的主要用途
  • 延迟执行是 curry 的重要使用场景

关于JS每日一题

JS每日一题可以看成是一个语音答题社区
每天利用碎片时间采用60秒内的语音形式来完成当天的考题
群主在次日0点推送当天的参考答案

  • 注 绝不仅限于完成当天任务,更多是查漏补缺,学习群内其它同学优秀的答题思路

点击加入答题

回到顶部