【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中一个非常强大的技术,它可以使代码更加灵活和可复用。在某些特定场景下,使用函数科里化可以简化代码并提高开发效率。

相关文章
|
4天前
|
JavaScript
js中有哪些函数?
js中有哪些函数?
5 0
|
4天前
|
JavaScript 前端开发 Java
JavaScript 特殊函数
JavaScript 特殊函数
6 0
|
4天前
|
JavaScript 前端开发
JavaScript 函数中break,continue,return 的区别
JavaScript 函数中break,continue,return 的区别
13 0
|
4天前
|
JavaScript 前端开发
JS - 立即执行函数
这篇文章解释了JavaScript中的立即执行函数(IIFE,Immediately Invoked Function Expression)的概念和用法,它用于创建局部作用域以避免全局变量的污染。文中提供了多种立即执行函数的示例,展示了如何通过不同的语法结构立即调用函数。
10 0
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
59 2
|
16天前
|
JavaScript 前端开发
JS:一篇文章带你搞懂什么是异步
JS:一篇文章带你搞懂什么是异步
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
54 4
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物交易平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物交易平台附带文章源码部署视频讲解等
46 4
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的大学生入伍人员管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的大学生入伍人员管理系统附带文章源码部署视频讲解等
59 4

热门文章

最新文章