JavaScript也玩私家订制——玩转函数柯里化

函数式编程是一种被部份JavaScript程序员推重的编程作风,更别说 Haskell 和 Scala 这类以函数式为教义的言语。缘由是由于其能用较短的代码完成功用,假如控制妥当,能到达代码文档化(代码自身具有很高可读性以至能够替代文档)的效果,固然,众多运用也会使代码可读性变差。

柯里化(Currying)是一个属于函数式编程的一个罕见的技能。简朴来讲,函数柯里化就是对高阶函数的降阶处置惩罚。
我们看下面这个函数:

function loc (a,b,c){
    console.log(a+'-'+b+'-'+c);
}

loc('浙江','杭州','西湖区');//>>>浙江-杭州-西湖区

这是一个吸收三个地名字符串的函数,功用是将三个地名字符串拼接到一同成为一个细致的地点。
我们尝尝只传入两个参数:

loc('浙江','杭州');//>>>浙江-杭州-undefined

毫无疑义地,这个函数照样会一般实行,只是底本属于“区”的位置由于没有吸收到参数而成了undefined

实在这类状况很多,比方我们还要天生浙江-杭州-余杭区浙江-杭州-拱墅区如许的地名,然则我们没必要每次都从新把浙江-杭州从新拼接一遍,所以你是否是会想,能不能只经由过程一个函数,把已拼接过的字符串缓存起来,只去拼接新的字符串呢?我们也许能够把之前的函数改一下:

function loc (a) {
    return function(b){
        return function(c){
            console.log(a+'-'+b+'-'+c);
        }
    }
}

好新鲜!这个loc函数只吸收一个参数,而返回一个新的函数,这个函数也只接收一个参数,内里一样返回一个函数,末了一个函数才返回三个参数拼接的字符串。
看起来是一个嵌套关联,好吧,让我们看看它是否能完成方才的主意:

var Zhejiang = loc('浙江');
var Hangzhou = Zhejiang('杭州');

var Xihu = Hangzhou('西湖区');           //浙江-杭州-西湖区
var Yuhang = Hangzhou('余杭区');         //浙江-杭州-余杭区
var Lucheng = Zhejiang('温州')('鹿城区'); //浙江-温州-鹿城区

看,经由过程如许的情势,我们轻松完成定制化函数啦!loc('杭州')不会急着把地名都拼接好,而是把杭州先存到闭包中,在须要拼接的时刻才用到它。

让你不测的是,这就是柯里化的基础思想,简朴地让人猝不及防。

不,这不是你想要的效果,最少你已考虑到一种恐惧的状况:假如参数有很多——比方100个,是否是要写一个嵌套一百次的函数?

幸亏,我们能够写一个通用函数来文雅地建立柯里化函数:

function curry(fn) {
    var outerArgs = Array.prototype.slice.call(arguments, 1);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments),
            finalArgs = outerArgs.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}

有了这个基础函数以后,我们能够柯里化其他一般函数:

//一个一般函数
function loc(a,b,c){
    console.log(a+'-'+b+'-'+c);
}

var workIn = curry(loc,'浙江','杭州','余杭区');
workIn();// >>> 浙江-杭州-余杭区

固然也能够如许定制:

var zj = curry(loc,'浙江');
var city = curry(zj,'杭州');

city('余杭区');    //>>> 浙江-杭州-余杭区
city('上城区');    //>>> 浙江-杭州-上城区
zj('温州','鹿城区');//>>> 浙江-温州-鹿城区

几乎文雅。

以下我们来简朴剖析以下这个通用函数:

function curry(fn) {
    var outerArgs = Array.prototype.slice.call(arguments, 1);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments),
            finalArgs = outerArgs.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}

我们看这个curry函数,显现接收一个参数,那就是须要被柯里化的函数。同时,由于JS奇异的函数传参,我们能够在curry继承放更多的参数,这些参数在函数体内部将以参数列表的情势存在,你能够经由过程arguments援用这个参数列表。注重,arguments援用的是一个参数列表而不是数组(虽然很像),所以数组的很多要领它都没有。固然,这个难不倒我们,还记得我上一篇文章里提到的apply()黑科技吗?传送门:《疾速明白JavaScript中apply()和call()的用法和用处》

outerArgs就是猎取除了第一个参数以外的参数列表。

而在返回的函数里,innerArgs猎取的是挪用这个返回函数时传入的一切参数,比方之前city('上城区')内里的’上城区’。

finalArgs则是拼接这两个数组(注重此时两个参数列表都已是正宗的数组,所以才能够运用concat要领)。

末了,运用apply,把一切参数构成的列表传入到本来的函数,实在质就是在挪用原始的函数,由于此时的参数都已完全。

末端福利:

《JavaScript也玩私家订制——玩转函数柯里化》

    原文作者:条件状语从句
    原文地址: https://segmentfault.com/a/1190000004589338
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞