JS复习 -- 函数柯里化

来源:互联网 发布:五金行业erp软件报价 编辑:程序博客网 时间:2024/06/06 07:45

柯里化,该词来源于英文单词Currying,感觉是好深奥的一个词。
我记住它的方式是:柯里化 –> 颗粒化。也就是将使用多个参数的函数转化成一系列使用一个参数的函数的方法。颗粒化嘛。

例子:

function add(a, b) {    return a + b;}// 执行 add 函数,一次传入两个参数即可add(1, 2) // 3// 假设有一个 curry 函数可以做到柯里化var addCurry = curry(add);addCurry(1)(2) // 3

实现方式

// 第一版var curry = function (fn) {    var args = [].slice.call(arguments, 1);    return function() {        var newArgs = args.concat([].slice.call(arguments));        return fn.apply(this, newArgs);    };};

代码解析:

curry函数接受一个函数作为第一个参数,但是curry函数还有可能接受更多参数,我们可以通过var args = [].slice.call(arguments, 1);这样的方式,将curry的第2、3…..个参数提取出来。

然后,curry函数返回了一个匿名函数。执行这个返回的匿名函数,首先将会拼接该匿名函数和最一开始的传入curry函数的所有参数,得到newArgs,然后,将这个合并了的参数数组,传入最一开始需要被柯里化的函数中,并执行这个函数。

使用方法:

function add(a, b) {    return a + b;}var addCurry = curry(add, 1, 2);addCurry() // 3//或者var addCurry = curry(add, 1);addCurry(2) // 3//或者var addCurry = curry(add);addCurry(1, 2) // 3

看懂了这一版代码,就可以发现,这已经有一些柯里化的感觉了。但是,还没有达到我们的要求。比如,对参数的个数的限制等,并没有考虑的很周全,

下面我们来看改进后的第二版代码。

// 第二版// 第一版的代码在这里变成了一个辅助函数哦function sub_curry(fn) {    var args = [].slice.call(arguments, 1);    return function() {        return fn.apply(this, args.concat([].slice.call(arguments)));    };}function curry(fn, length) {    length = length || fn.length; // 获取函数fn的参数个数    var slice = Array.prototype.slice;    return function() { // 返回一个匿名函数        if (arguments.length < length) {         // 如果执行这个匿名函数的时候,传入的参数长度小于需要柯里化的函数.....            var combined = [fn].concat(slice.call(arguments));            // .....那么就将传入的需要柯里化的函数和本次调用的参数组合成数组,传入sub_curry函数中(上面我们解析过这个函数的,它的第一个参数应该是一个函数,这也就是为什么要写[fn].concat.....)            return curry(sub_curry.apply(this, combined), length - arguments.length);            // 然后,继续返回一个curry函数,将我们还需要的参数个数作为本函数的第二个参数传入。        } else {            return fn.apply(this, arguments);        }    };}

其实柯里化的核心思想就是,利用高阶函数,如果分步传入的参数个数够了,就执行,如果不够,就返回一个函数,继续等待参数。

验证:

var fn = curry(function(a, b, c) {    return [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"]