JS 柯里化 (curry)
用 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) {
// ...
}
函数 fn 接受两个参数(2-arity 函数),_fn 接受三个参数(3-arity 函数)。
因此,currying 将具有多个参数的函数转换为一系列函数,每个函数都接收一个参数。
我们来看一个简单的例子:
function multiply(a, b, c) {
return a * b * c;
}
此函数接收三个数字,将数字相乘并返回结果。
multiply(1, 2, 3) // 6
请参阅我们如何使用完整参数调用 multiply 函数,来创建一个 curried 版本函数,看看我们如何在一系列调用中调用相同的函数(并得到相同的结果):
function multiply(a) {
return (b) => {
return (c) => {
return a * b * c;
}
}
}
log(multiply(1)(2)(3)) // 6
我们已将 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
让我们一个接一个地接收参数。我们把 1 传递给了 multiply 函数:
let mul1 = multiply(1);
它返回这个函数:
return (b) => {
return (c) => {
return a * b * c;
}
}
现在,mul1 保持上面的函数定义,它带有一个参数 b。
我们调用了 mul1 函数,传入 2:
let mul2 = mul1(2);
在 mul2 中将返回第三个函数:
return (c) => {
return a * b * c;
}
返回的函数现在存储在 mul2 变量中。
从本质上讲,mul2 将是:
mul2 = (c) => {
return a * b * c;
}
当 mul2 以 3 作为参数调用时,
const result = mul2(3);
它把之前传入的参数 a = 1,b = 2 带入计算并返回结果 6。
log(result); // 6
作为嵌套函数,mul2 可以访问外部函数 multiply 以及 mul1 作用域内的变量。
这就是为什么 mul2 能使用已经在的函数中定义的变量并执行乘法运算的原因。虽然这些函数早已在内存中被回收 garbage collected,但它的变量仍以某种方式保留 "alive"。
您会看到三个数字一次一个地应用于该函数,并且每次都返回一个新函数,直到所有数字都用完为止。
让我们看另一个例子:
function volume(l, w, h) {
return l * w * h;
}
const aCylinder = volume(100, 20, 90); // 180000
我们有一个计算实心物体体积的函数 volume。
柯里化后的版本将接受一个参数并返回一个函数,该函数也将接收一个参数并返回一个函数。这个过程将被循环/继续,直到到达最后一个参数并返回最后一个函数,这将执行与前一个参数和最后一个参数的乘法运算。
function volume(l) {
return (w) => {
return (h) => {
return l * w * h;
}
}
}
const aCylinder = volume(100)(20)(90) // 180000
与我们在 multiply 函数中所使用的一样,最后一个函数只接受 h ,但是它将执行的操作所用到的其他函数作用域内的变量早已被函数返回。因为闭包 Closure ,这些参数仍然有效。
currying 背后的想法是接收一个函数并返回一个特殊函数的函数。
数学中的 Currying
我有点喜欢数学例证
JS 柯里化 (curry)的更多相关文章
- Scala 基础(十二):Scala 函数式编程(四)高级(二)参数(类型)推断、闭包(closure)、函数柯里化(curry)、控制抽象
1 参数(类型)推断 参数推断省去类型信息(在某些情况下[需要有应用场景],参数类型是可以推断出来的,如list=(1,2,3) list.map() map中函数参数类型是可以推断的),同时也可以 ...
- js 柯里化Currying
今天读一篇博客的时候,看都有关柯里化的东西,由于好奇,特意查了一下,找到一篇比较好的文章,特意收藏. 引子先来看一道小问题:有人在群里出了到一道题目:var s = sum(1)(2)(3) .... ...
- JS - 柯里化
一:what's this? 柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.其实,柯里化就是用闭包原理实现函数 ...
- Javascript函数柯里化(curry)
函数柯里化currying,是函数式编程非常重要的一个标志.它的实现需要满足以下条件,首先就是函数可以作为参数进行传递,然后就是函数可以作为返回值return出去.我们依靠这个特性编写很多优雅酷炫的代 ...
- js柯里化的一个应用
听到同学说面试一道题目 add(1)(2)(3)(4); 查询了下资料 这是一个js里面的柯里化 现象 add_curry防范返回的是一个 retVal,并不是执行结果.这里的代码很想递归,但是不是 ...
- 函数柯里化 curry
一.函数柯里化的特性: (1)参数复用 $.ajax // 示例一 function ajax(type,url,data) { var xhr = new XMLHttpRequest(); xhr ...
- js柯里化
这篇文章讲的很好啊~例子很好 http://www.zhangxinxu.com/wordpress/2013/02/js-currying/ 这篇是讲函数式编程的,其中也有涉及到,说明了柯里化是一种 ...
- js 柯里化、深拷贝、浅拷贝
curry const sum = (a, b, c, d) => a + b + c + d const curry = fn => (judge = (...args) => a ...
- js函数式编程(二)-柯里化
这节开始讲的例子都使用简单的TS来写,尽量做到和es6差别不大,正文如下 我们在编程中必然需要用到一些变量存储数据,供今后其他地方调用.而函数式编程有一个要领就是最好不要依赖外部变量(当然允许通过参数 ...
随机推荐
- vue项目的架构设计完善详解
vue项目构建vuex+mock层 vue项目添加jsBridge(与原生交互的) vue项目添加代码格式化
- Redis后台监控与管理CacheCloud
CacheCloud环境需求 Java 7 Maven 3 MySQL Redis 3 具体用法可参考:https://cachecloud.github.io 1.下载CacheCloud 官网ht ...
- (3)lscpu详解 (每周一个linux命令系列)
(3)lscpu详解 (每周一个linux命令系列) linux命令 lscpu详解 引言:今天的命令是用来看cpu信息的lscpu lscpu 我们先看man lscpu display infor ...
- Domain Adaptation (1)选题讲解
1 所选论文 论文题目: <Unsupervised Domain Adaptation with Residual Transfer Networks> 论文信息: NIPS2016, ...
- all与any的用法
all函数:检测矩阵中是否全为非零元素 any函数:检测矩阵中是否有非零元素,如果有,则返回1,否则,返回0.用法和all一样 语法: B = all(A) B = all(A, dim) 复制代码 ...
- PAT A1124 Raffle for Weibo Followers (20 分)——数学题
John got a full mark on PAT. He was so happy that he decided to hold a raffle(抽奖) for his followers ...
- 【Codeforces 464D】World of Darkraft - 2
Codeforces 464 D 首先我们知道这K个装备是互不干扰的,就是说如果一个装备升级了或者卖掉了,不会对其它装备的挣到的钱产生任何影响.所以我们就考虑单独处理某一个装备挣到的钱. 那么就设\( ...
- QT 布局管理器的使用
很多的时候,需要布局管理器的使用, 在此介绍一下布局管理器的使用,直接上代码 #include "widget.h" #include "ui_widget.h" ...
- Luogu P2661 [NOIP2015] 信息传递
qwq 今天做完并查集突然想起来这道以前做的好(shui)题, 虽然是黄题,但是是并查集一个比较特别的用法 这道题大概可以用求最小环的方式来做,但是从直觉上果然还是并查集w 乍一看只要求出“父→子”即 ...
- java 面向对象String类
1.String类:String 是不可变字符序列 1) char charAt(int index)返回字符串中第 index 个字符. 2) boolean equalsIgnoreCase(St ...