用 JS 理解柯里化

函数式编程风格,试图以函数作为参数传递(回调)和无副作用的返回函数(修改程序的状态)。

很多语言采用了这种编程风格。JavaScript,Haskell,Clojure,Erlang 和 Scala 是其中最受欢迎的几种语言。

数式编程风格具有传递和返回函数的能力,它带来了许多概念:

  • Pure Functions(纯函数)
  • Currying(柯里化)
  • Higher-Order functions(高阶函数)

我们将在这里介绍这些概念中的一种 Currying。

在本文中,我们将看到 currying 如何工作,以及它如何在软件开发人员的工作中发挥作用。

提示:您可以将其变为 Bit组件,而不是复制粘贴可重用的 JS 功能,并快速与团队共享项目。

Bit - 使用代码组件共享和构建
Bit 可帮助您在项目和应用程序之间共享,发现和使用代码组件,以构建新功能和...       bitsrc.io

什么是 Currying?

Currying 是函数式编程中的一个过程,我们可以将具有多个参数的函数转换为顺序嵌套的函数。它返回一个接收下一个参数的新函数。

它不断返回一个新函数(接收当前参数,就像我们之前所说的那样),直到所有参数都用完为止。保留参数 "alive"(通过闭包),并且当返回并执行 currying 链中的最终函数时,所有参数都在执行中使用。

Currying 是将具有多个 arity 的函数转换为具有较少 arity 的函数的过程 -  Kristina Brainwave

注意:术语 arity “是指函数所接收的参数个数”。例如,

function fn (a, b) {
// ...
} function _fn(a, b, c) {
// ...
}
Js

函数 fn 接受两个参数(2-arity 函数),_fn 接受三个参数(3-arity 函数)。

因此,currying 将具有多个参数的函数转换为一系列函数,每个函数都接收一个参数。

我们来看一个简单的例子:

function multiply(a, b, c) {
return a * b * c;
}
Js

此函数接收三个数字,将数字相乘并返回结果。

multiply(1, 2, 3) // 6
Js

请参阅我们如何使用完整参数调用 multiply 函数,来创建一个 curried 版本函数,看看我们如何在一系列调用中调用相同的函数(并得到相同的结果):

function multiply(a) {
return (b) => {
return (c) => {
return a * b * c;
}
}
} log(multiply(1)(2)(3)) // 6
Js

我们已将 multiply(1,2,3) 函数调用转为 multiply(1)(2)(3) 多个函数调用。

我们已经将一个函数转为一系列函数。为了得到三个数相乘的结果 12 和 3 三个数字一个接一个地传递,每个数字都将在下一个函数的内部调用。我们可以将 multiply(1)(2)(3) 分开以便更好地理解它:

const mul1 = multiply(1);
const mul2 = mul1(2);
const result = mul2(3);
log(result); // 6
Js

让我们一个接一个地接收参数。我们把 1 传递给了 multiply 函数:

let mul1 = multiply(1);
Js

它返回这个函数:

return (b) => {
return (c) => {
return a * b * c;
}
}
Js

现在,mul1 保持上面的函数定义,它带有一个参数 b

我们调用了 mul1 函数,传入 2

let mul2 = mul1(2);
Js

在 mul2 中将返回第三个函数:

return (c) => {
return a * b * c;
}
Js

返回的函数现在存储在 mul2 变量中。

从本质上讲,mul2 将是:

mul2 = (c) => {
return a * b * c;
}
Js

当 mul2 以 3 作为参数调用时,

const result = mul2(3);
Js

它把之前传入的参数 a = 1b = 2 带入计算并返回结果 6

log(result); // 6
Js

作为嵌套函数,mul2 可以访问外部函数 multiply 以及 mul1 作用域内的变量。

这就是为什么 mul2 能使用已经在的函数中定义的变量并执行乘法运算的原因。虽然这些函数早已在内存中被回收 garbage collected,但它的变量仍以某种方式保留 "alive"

您会看到三个数字一次一个地应用于该函数,并且每次都返回一个新函数,直到所有数字都用完为止。

让我们看另一个例子:

function volume(l, w, h) {
return l * w * h;
} const aCylinder = volume(100, 20, 90); // 180000
Js

我们有一个计算实心物体体积的函数 volume

柯里化后的版本将接受一个参数并返回一个函数,该函数也将接收一个参数并返回一个函数。这个过程将被循环/继续,直到到达最后一个参数并返回最后一个函数,这将执行与前一个参数和最后一个参数的乘法运算。

function volume(l) {
return (w) => {
return (h) => {
return l * w * h;
}
}
} const aCylinder = volume(100)(20)(90) // 180000
Js

与我们在 multiply 函数中所使用的一样,最后一个函数只接受 h ,但是它将执行的操作所用到的其他函数作用域内的变量早已被函数返回。因为闭包 Closure ,这些参数仍然有效。

currying 背后的想法是接收一个函数并返回一个特殊函数的函数。

数学中的 Currying

我有点喜欢数学例证

JS 柯里化 (curry)的更多相关文章

  1. Scala 基础(十二):Scala 函数式编程(四)高级(二)参数(类型)推断、闭包(closure)、函数柯里化(curry)、控制抽象

    1  参数(类型)推断 参数推断省去类型信息(在某些情况下[需要有应用场景],参数类型是可以推断出来的,如list=(1,2,3) list.map() map中函数参数类型是可以推断的),同时也可以 ...

  2. js 柯里化Currying

    今天读一篇博客的时候,看都有关柯里化的东西,由于好奇,特意查了一下,找到一篇比较好的文章,特意收藏. 引子先来看一道小问题:有人在群里出了到一道题目:var s = sum(1)(2)(3) .... ...

  3. JS - 柯里化

    一:what's this? 柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.其实,柯里化就是用闭包原理实现函数 ...

  4. Javascript函数柯里化(curry)

    函数柯里化currying,是函数式编程非常重要的一个标志.它的实现需要满足以下条件,首先就是函数可以作为参数进行传递,然后就是函数可以作为返回值return出去.我们依靠这个特性编写很多优雅酷炫的代 ...

  5. js柯里化的一个应用

    听到同学说面试一道题目 add(1)(2)(3)(4); 查询了下资料  这是一个js里面的柯里化 现象 add_curry防范返回的是一个 retVal,并不是执行结果.这里的代码很想递归,但是不是 ...

  6. 函数柯里化 curry

    一.函数柯里化的特性: (1)参数复用 $.ajax // 示例一 function ajax(type,url,data) { var xhr = new XMLHttpRequest(); xhr ...

  7. js柯里化

    这篇文章讲的很好啊~例子很好 http://www.zhangxinxu.com/wordpress/2013/02/js-currying/ 这篇是讲函数式编程的,其中也有涉及到,说明了柯里化是一种 ...

  8. js 柯里化、深拷贝、浅拷贝

    curry const sum = (a, b, c, d) => a + b + c + d const curry = fn => (judge = (...args) => a ...

  9. js函数式编程(二)-柯里化

    这节开始讲的例子都使用简单的TS来写,尽量做到和es6差别不大,正文如下 我们在编程中必然需要用到一些变量存储数据,供今后其他地方调用.而函数式编程有一个要领就是最好不要依赖外部变量(当然允许通过参数 ...

随机推荐

  1. centos7下安装docker(13docker存储)

    Docker为容器提供了两种存放数据的资源: 1.storage driver管理的镜像层和容器层 2.Data volume Storage driver 之前我们学习镜像的时候知道镜像的分层结构: ...

  2. tomcat健康检查监控脚本

    #!/bin/sh#自动监控tomcat脚本并且执行重启操作#获取tomcat_IDTomcatID=`ps -ef|grep tomcat|grep -v "grep"|grep ...

  3. [题目] luogu P2061 [USACO07OPEN]城市的地平线City Horizon

    算法 线段树 + 离散化 思路 对\((x,y,h)\)的左右端点\(x,y\)进行离散化,离散化前的原值记为\(val[i]\),对每个矩形按高度\(h\)从小到大排序. 设离散化后的端点有\(M\ ...

  4. metamask源码学习-contentscript.js

    When a new site is visited, the WebExtension creates a new ContentScript in that page's context, whi ...

  5. 按行读取.txt文件,并按行写入到新文件中

    package com.test.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Fi ...

  6. 深入浅出的webpack构建工具---DevServer配置项(二)

    深入浅出的webpack构建工具---DevServer配置项(二) 阅读目录 DevServer配置项 1. contentBase 2. port 3. host 4. headers 5. hi ...

  7. java 日期与时间类

    1.Date类:  https://www.cnblogs.com/huangminwen/p/5994927.html 2.DateFormat和SimpleDateFormat (simple简单 ...

  8. [01] JSP的基本认识

    1.什么是JSP JSP,全称JavaServer Pages,是由Sun Microsystems公司倡导和许多公司参与共同建立的一种使软件开发者可以响应客户端请求,而动态生成HTML.XML或其他 ...

  9. [04] 高级映射 association和collection

    之前我们提到的映射,都是简单的字段和对象属性一对一,假设对象的属性也是一个对象,即涉及到两个表的关联,此时应该如何进行映射处理? 先看两张表,author 和 book:    业务上对应关系为,一个 ...

  10. 自建mvc5项目里几个类图

    AccoutController.cs AccountViewModels.cs IdentityModel.cs