【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(一)

简介: 【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(一)

在之前的两篇文章:

我介绍了JS函数式编程中的一些概念及其实践,本文则着重详细、深入介绍里面最常用的技术之一 —— 函数柯里化。

柯里化(Currying)

柯里化(Currying)是一种关于函数的高阶技术,它允许你将一个有多个参数的函数转化为一连串的函数,它返回一个新的函数,等待下一个参数的内联。换句话说,一个函数不是一次接受所有的参数,而是接受第一个参数并返回一个新的函数,该函数接受第二个参数并返回一个新的函数,该函数接受第三个参数,以此类推,直到所有参数都得到满足。

这个概念是以数学家 Haskell Curry 的名字命名的,他在1930年代提出了这个概念。在JavaScript中,Currying 是一个强大的工具,它可以将一个有多个参数的函数转化为一系列嵌套的函数,每个函数只接受一个参数。Currying 帮助你避免多次传递同一个变量,并帮助你创建一个高阶函数。可以提高代码的可重用性、可组合性和可维护性。

在本文中,我们将深入探讨curry,提供全面的解释和例子。

柯里化有两个特点:

  1. 柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)
  2. 柯里化不会调用函数。它只是对函数进行转换。

先来看一个例子,创建一个辅助函数 curry(f),该函数将对两个参数的函数 f 执行柯里化。换句话说,对于两个参数的函数 f(a, b) 执行 curry(f) 会将其转换为以 f(a)(b) 形式运行的函数:

function curry(f) { // curry(f) 执行柯里化转换
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}
// 用法
function sum(a, b) {
  return a + b;
}
let curriedSum = curry(sum);
alert( curriedSum(1)(2) ); // 3

正如你所看到的,实现非常简单:只有两个包装器(wrapper)。

  • curry(func) 的结果就是一个包装器 function(a)
  • 当它被像 curriedSum(1) 这样调用时,它的参数会被保存在词法环境中,然后返回一个新的包装器 function(b)
  • 然后这个包装器被以 2 为参数调用,并且,它将该调用传递给原始的 sum 函数。

柯里化更高级的实现,例如 lodash 库的 _.curry,会返回一个包装器,该包装器允许函数被正常调用或者以部分应用函数(partial)的方式调用:

function sum(a, b) {
  return a + b;
}
let curriedSum = _.curry(sum); // 使用来自 lodash 库的 _.curry
alert( curriedSum(1, 2) ); // 3,仍可正常调用
alert( curriedSum(1)(2) ); // 3,以部分应用函数的方式调用

函数科里化(Currying)是JavaScript中的一个高级特性,它能够将接受多个参数的函数变成一系列只接受部分参数的函数。这种技术在函数式编程中经常使用,并且可以使代码更加灵活和可复用。以下是一个详细的js代码示例,展示了如何实现函数科里化。

// 定义一个普通的函数,它接收两个参数并返回他们的和
function add(x, y) {
  return x + y;
}
// 编写一个curry函数,它可以对任何函数进行科里化
function curry(fn) {
  // 获取除第一个参数外的其他参数
  var args = Array.prototype.slice.call(arguments, 1);
  // 返回一个新函数,如果参数足够执行则调用原来的函数,否则继续科里化
  return function() {
    var newArgs = args.concat(Array.prototype.slice.call(arguments));
    if (newArgs.length >= fn.length) {
      return fn.apply(this, newArgs);
    } else {
      return curry.call(this, fn, ...newArgs);
    }
  };
}
// 使用curry函数对add进行科里化
var curriedAdd = curry(add);
// 调用curriedAdd函数,返回一个新函数
var add1 = curriedAdd(1);
// 继续调用新函数,返回结果2
console.log(add1(1)); // 2
// 另一种调用方式
console.log(curriedAdd(2)(3)); // 5

在上面的代码中,我们首先定义了一个普通的函数add,它接收两个参数并返回他们的和。然后,我们编写了一个名为curry的函数,它接受一个要进行科里化的函数作为第一个参数,并且通过Array.prototype.slice.call(arguments, 1)获取除了第一个参数外的其他参数。

curry函数内部,我们返回了一个新函数,这个新函数如果接收到的参数足够执行,则调用原来的函数。否则,继续使用curry函数对其进行科里化。这个过程通过newArgs变量将之前传入的参数和当前传入的参数合并起来实现。最后,我们通过return curry.call(this, fn, ...newArgs);递归调用curry函数,直到参数足够执行时结束递归调用。

我们使用curry函数对add函数进行科里化,得到一个名为curriedAdd的函数。我们可以使用curriedAdd函数来创建新的函数,例如使用curriedAdd(1)返回一个只需要一个参数的新函数。当我们调用这个新函数时,它会返回一个结果,而不是立即执行。当我们重新调用这个函数,将它的返回值和另一个参数一起传入时,它会再次返回结果,依此类推。

总之,函数科里化是JavaScript中一个非常强大的技术,它可以使代码更加灵活和可复用。在某些特定场景下,使用函数科里化可以简化代码并提高开发效率。

相关文章
|
24天前
|
JavaScript
变量和函数提升(js的问题)
变量和函数提升(js的问题)
|
24天前
|
JavaScript
常见函数的4种类型(js的问题)
常见函数的4种类型(js的问题)
11 0
|
25天前
|
JavaScript
写一个函数将N组<>(包含开始和结束),进行组合,并输出组合结果 (js)
写一个函数将N组<>(包含开始和结束),进行组合,并输出组合结果 (js)
10 0
|
4天前
|
JavaScript 前端开发
js开发:请解释什么是ES6的Generator函数,以及它的用途。
ES6的Generator函数是暂停/恢复功能的特殊函数,利用yield返回多个值,适用于异步编程和流处理,解决了回调地狱问题。例如,一个简单的Generator函数可以这样表示: ```javascript function* generator() { yield 'Hello'; yield 'World'; } ``` 创建实例后,通过`.next()`逐次输出"Hello"和"World",展示其暂停和恢复的特性。
15 0
|
11天前
|
缓存 JavaScript 前端开发
js的入口函数,入口函数的作用
js的入口函数,入口函数的作用
15 4
|
26天前
|
存储 前端开发 JavaScript
JavaScript如何封装一些常见的函数来提高工作效率
通过封装这些常见函数,你可以在项目中重复使用,提高代码的复用性和工作效率。这些函数包括获取元素、发起Ajax请求、处理本地存储、日期格式化、定时器等功能,可以在不同场景中减少重复的代码编写。
8 0
JavaScript如何封装一些常见的函数来提高工作效率
|
1月前
|
JavaScript
js开发:请解释什么是ES6的Generator函数,以及它的用途。
ES6的Generator函数是暂停恢复的特殊函数,用yield返回多个值,适用于异步编程和流处理,解决了回调地狱问题。
16 6
|
2月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
27 0
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
77 0
|
5天前
|
JavaScript 前端开发 测试技术
学习JavaScript
【4月更文挑战第23天】学习JavaScript
11 1