用 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) 多个函数调用。

我们已经将一个函数转为一系列函数。为了得到三个数相乘的结果 1,2 和 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 = 1,b = 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. DevExpress gridcontrol gridView主从表折叠/展开显示

    在使用报表的时候,有很多需要主从表一起显示,从表不需要另外弹窗显示明细,反而直接显示在主表下方.如图所示: 第一次做这个功能,主从表显示,从表列隐藏,从表单元格点击事件这三个功能点花费了很多时间,在网 ...

  2. C#反射の反射详解

    C#反射の反射详解(点击跳转)C#反射の反射接口(点击跳转)C#反射反射泛型接口(点击跳转)C#反射の一个泛型反射实现的网络请求框架(点击跳转) 一.什么是反射 反射(Reflection):这是.N ...

  3. C++整形转化成string类型---路径拼接在批处理程序中的应用

    上"酸菜" // show_dateset_image.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include ...

  4. 在php中分别使用curl的post提交数据的方法和get获取网页数据的方法

    在php中分别使用curl的post提交数据的方法和get获取网页数据的方法整理分享一下额,具体代码如下: (1)使用php curl获取网页数据的方法: $ch=curl_init(); //设置选 ...

  5. 老男孩Python自动化运维视频

    链接:https://pan.baidu.com/s/1VLXJ0RZr39kpSGthkLkgmA 密码私聊我

  6. centos 7部署openvpn easy-rsa 3.0部署方法

    yum install openvpn easy-rsa openssl-devel mkdir -p /etc/openvpn/easy-rsa/cp -p /usr/share/doc/easy- ...

  7. (转)Docker磁盘垃圾清理

    文章转自https://mp.weixin.qq.com/s/S8ZjGZF8oLC8c1JRnkE5yw?tdsourcetag=s_pctim_aiomsg 1.整体分析 对于Docker来说,存 ...

  8. matlab:inv,pinv逆与伪逆

    对于方阵A,如果为非奇异方阵,则存在逆矩阵inv(A)对于奇异矩阵或者非方阵,并不存在逆矩阵,但可以使用pinv(A)求其伪逆   inv:   inv(A)*B实际上可以写成A\BB*inv(A)实 ...

  9. 关于TerraBuilder的扩展开发

    熟悉Skyline的朋友,可能会发现,在最新的6.6的产品体系中,TerraBuilder中用于生成三维地形场景的模块,改成了TerrainBuilder. 通常情况下,这款软件模块,我们主要用它来进 ...

  10. 开发板测试-GPRS

    注意事项: 经过测试,为了使STM32和Air202的串口稳定通信,需要更改 以前电路感觉应该是三极管控制极4.7K电阻太大,又因为开关速度快,然后开关的时候导致不足以让三极管处于全部导通状态,所以电 ...