美文网首页
JS函数柯里化

JS函数柯里化

作者: 天問_专注于大前端技术 | 来源:发表于2022-01-19 23:32 被阅读0次

    在正式聊函数柯里化之前,我这里给大家补充下高阶函数的概念和应用:

    1.1、什么是高阶函数?
    高阶函数英文叫 Higher-order function,它的定义很简单,就是至少满足下列一个条件的函数:

    接受一个或多个函数作为输入
    输出一个函数
    也就是说高阶函数是对其他函数进行操作的函数,可以将它们作为参数传递,或者是返回它们。 简单来说,高阶函数是一个接收函数作为参数传递或者将函数作为返回值输出的函数。

    1.2、高阶函数例子
    其实平时开发中经常会用到高阶函数,只是之前你不清楚其概念而已,来看下下面几个函数:

    Array.prototype.map
    Array.prototype.filter
    Array.prototype.reduce
    Array.prototype.sort
    这三个数组的方法函数就是高阶函数,因为它们都接收一个回调函数作为参数,满足第一个条件

    高阶函数其中一个优点就是在某种情况下可以让代码更加简洁,我们就拿map方法来举例,如果不用map这个高阶方法的话,要实现对一个现有数组中每个元素*2的需求

    不使用高阶函数:

    const arr1 = [1, 2, 3, 4];
    const arr2 = [];
    for (let i = 0; i < arr1.length; i++) {
    arr2.push( arr1[i] * 2);
    }
    console.log( arr2 );
    // [2, 4, 6, 8]
    console.log( arr1 );
    // [1, 2, 3, 4]

    使用map高阶函数:

    const arr1 = [1, 2, 3, 4];
    const arr2 = arr1.map(item => item * 2);
    console.log( arr2 );
    // [2, 4, 6, 8]
    console.log( arr1 );
    // [1, 2, 3, 4]

    从上面例子中不难看出用map方法可以轻松实现上述需求,其他两个方法其实也是同样的道理,这里就不多叙述了

    二、函数柯里化
    2.1、定义
    函数柯里化又叫部分求值,维基百科中对柯里化 (Currying) 的定义为:

    在数学和计算机科学中,柯里化是一种将使用多个参数的函数转换成一系列使用一个参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    用大白话来说就是只传递给函数一部分参数来调用它,让它返回一个新函数去处理剩下的参数

    相信部分同学看完这个概念还是有点稀里糊涂,我们来看个简单例子说明下

    function url (a,b,c){
    return ${a}://www.${b}.${c}
    }
    const url1 = url('https',"baidu",'com')
    console.log(url1) // "https://www.baidu.com"

    上面这个url函数接受三个参数,最终函数返回一个完整的url地址,这是普通写法,然后我们来看下函数柯里化后的写法是怎么样的?

    function url(a){
    return (b)=>{
    return (c)=>{
    return ${a}://www.${b}.${c}
    }
    }
    }
    const AA = url('https') // 他是一个函数
    const BB = AA('baidu') // 他是一个函数
    const CC = BB('com') // 他是一个函数
    console.log(CC) // "https://www.baidu.com"

    看到这我们再回过头来看下其概念定义,原先url函数接受多个参数,然后使用了柯里化技术,将其转换成了一系列接收一个参数的函数(url改写后内部就是返回多个接收单一入参的函数),并且返回接受余下的参数(url原先的其他参数b和c现通过其内部返回的其他函数来接收处理了),最终函数柯里化后还是会返回一个新结果的函数(上面例子最终返回的是一个接收参数c返回最终完整结果的函数),现在会不会好理解些了呢

    2.2、柯里化的应用(优点)
    1、参数复用

    还是可以用上面拼接完整url的例子来说明

    // DEMO1
    //原先的写法
    function url (a,b,c){
    return ${a}://www.${b}.${c}
    }
    const url1 = url('https','baidu','com')
    const url2 = url('https','jingdong','com')

    //柯里化处理后
    function url(a){
    return (b)=>{
    return (c)=>{
    return ${a}://www.${b}.${c}
    }
    }
    }
    const json1 = url('https');
    const url1 = json1('baidu')('com')
    const url2 = json1('jindong')('com')

    通过对函数柯里化处理后,在生成多个类似url地址时就可以复用相同的部分,不用重复传相同的参数,起到了参数复用的效果,我们还可以再继续巩固下,再来看个例子:

    //DEMO2
    // 原先正则校验字符串函数每次调用时需要重复传入正则表达式,如果正则表达式很长的话,是不是会显得繁琐
    function check(regexp,str){
    return regexp.test(str)
    }
    const result1 = check(/\d+/,'456') // true
    const result2 = check(/\d+/,'asd') // false

    // 函数柯里化后
    function check(regexp){
    return (str)=>{
    return regexp.test(str)
    }
    }
    const temp = check(/\d+/)
    const result1 = temp('456') // true
    const result2 = temp('asd') // false

    2、延迟调用

    js中的bind方法其实底层原理也是应用了柯里化技术,我们来看下代码:

    // 下面是bind方法的简易版代码
    function bind (ctx,...args){
    return ()=>{
    return this.apply(ctx,args) // 这里的this指的就是调用bind方法的那个函数
    }
    }
    var name = "windowName"; //全局name
    var age = 22; // 全局age
    const obj = {name: 'objName',age:11}
    function zhangsan (){
    return ${this.name}-${this.age}
    }
    zhangsan() //'windowName-22'
    zhangsan.bind(obj) // ƒ zhangsan (){return ${this.name}-${this.age}}
    zhangsan.bind(obj)() //'objName-11'

    说明:从上面bind方法可以看出,调用bind方法后它只是改变了内部this指向,并返回了一个函数,并没有立即执行该函数,如果想要得到结果,需要再次调用bind方法返回的那个函数才行,所以这点也就说明了柯里化函数有延迟调用的作用

    2.3、手写万能柯里化函数
    我们可以这么理解:所谓的柯里化函数,就是封装「一系列的处理步骤」,通过闭包将参数集中起来计算,最后再把需要处理的参数传进去。那如何实现 currying 函数呢?

    实现原理就是「用闭包把传入参数保存起来,当传入参数的数量足够执行函数时,就开始执行函数」。上面延迟计算部分已经实现了一个简化版的 currying 函数。

    相关文章

      网友评论

          本文标题:JS函数柯里化

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