柯里化其实就是这么回事,别被高大上的名词骗了——拒绝“八股文

什么是函数柯里化

函数柯里化 (Currying) 是一种将多个参数的函数转换为单个参数函数的技术,通过使用函数柯里化,可以提高代码的复用性和可维护性

举个例子,有一个求两数之和的函数:

function add(a, b) {
    return a + b;
}

如果把这个函数柯里化,就会变成:

function add(a) {
  return function(b) {
    return a + b;
  }
}

再来看一个例子,有一个求两数相乘并加上偏移量的函数:

function multiplyAndOffset(a, b, offset) {
  return a * b + offset;
}

我们可以把这个函数柯里化为:

function multiply(a) {
  return function(b) {
    return function(offset) {
      return a * b + offset;
    }
  }
}

使用柯里化之后,我们就可以这样调用:

multiply(2)(3)(1); // 7

为什么需要函数柯里化

函数柯里化在实际开发中有很多好处:

  • 函数复用:由于函数柯里化的特性,我们可以非常容易地为函数的一部分参数进行复用。例如,上面那个例子中的 multiply 函数,如果我们想要使用相同的 offset 参数,在调用时只需要传递两个参数就可以了
  • 延迟执行:柯里化使得函数的执行被延迟到最后一个参数被传递进来的时候再进行。这使得我们可以预先传递一些参数,并将剩余的参数留到稍后再决定,这在一些场景下非常有用,例如事件处理程序
  • 简单化函数:由于柯里化把多参数函数转化成了单参数函数,这使得函数接口更加简洁,更加容易使用
  • 函数组合:函数柯里化可以使得不同的函数更加容易组合起来使用,从而实现更加复杂的操作

如何实现函数柯里化

函数柯里化的本质就是通过闭包来返回一个函数,这个返回的函数会接收一个新的参数并返回一个新函数,这个新函数会再次接收一个参数并返回一个新的函数,以此类推直到最后一个参数被传递进来

下面是一个实现柯里化的简单示例:

    function add() {
      let sum = 0;
      return function innerFn(num) {
        if (num !== undefined) {
          sum += num;
          return innerFn;
        } else {
          return sum;
        }
      }
    }

    console.log(add()(1)(2)(3)()); // 输出 6

我们首先定义了一个 add 函数,它返回了一个内部函数 innerFn。在 innerFn 中,我们首先定义了一个变量 sum,用于保存累加的结果。当传入的参数不为 undefined 时,我们将其加到 sum 中,并返回 innerFn。这样就可以继续传递下一个参数了。当参数为 undefined 时,我们返回 sum,表示累加完毕

但是,这种简单的实现方式存在一个问题,那就是只能处理参数数量为 2 的函数,无法处理参数数量不确定的函数。因此我们需要更加通用的柯里化实现方式

这里是一个更加通用的函数柯里化的实现方式:

    function curry(fn) {
      return function curried(...args) {
        if (args.length >= fn.length) {
          return fn.apply(this, args);
        } else {
          return function(...args2) {
            return curried.apply(this, args.concat(args2));
          }
        }
      }
    }

该函数的参数是一个函数 fn,它返回一个柯里化后的函数。在函数内部,我们定义了一个 curried 函数,它的作用是接受函数需要的所有参数。当传入的参数数量大于或等于原函数需要的参数数量时,就直接调用原函数并返回结果;否则,返回一个新函数,然后使用闭包将当前已经传入的参数保存下来。这个新函数再次接受一个参数,并将这个参数与之前已经保存的参数合并,然后递归调用 curried 函数

我们可以使用如下方式调用 curry 函数:

    const add = (a, b, c) => a + b + c;
    const curriedAdd = curry(add);
    console.log(curriedAdd(1)(2)(3)); // 6
    console.log(curriedAdd(1, 2)(3)); // 6
    console.log(curriedAdd(1)(2, 3)); // 6
    console.log(curriedAdd(1, 2, 3)); // 6

这个函数柯里化实现方式比较通用,可以处理多种不同参数数量的函数

结语

函数柯里化是一种非常有用的编程技术,它可以提高代码的复用性、简化函数接口、延迟函数执行等。在实际开发中,我们可以使用函数柯里化来实现部分应用函数,处理数据,编写事件处理程序等。同时,我们也需要注意柯里化函数的性能问题,在一些大量调用的场景下需要注意函数执行次数以及闭包变量的使用,避免出现性能瓶颈

我是前端霸哥,愿你的代码中没有bug
写的不好的地方,欢迎各位小伙伴批评指正

全部评论

相关推荐

06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务