JavaScript函数式编程(纯函数、柯里化以及组合函数)

目录

  • JavaScript函数式编程(纯函数、柯里化以及组合函数)
    • 前言
    • 1.纯函数
      • 1.1.纯函数的概念
      • 1.2.副作用
      • 1.3.纯函数案例
    • 2.柯里化
      • 2.1.柯里化的概念
      • 2.2.函数柯里化的过程
      • 2.3.函数柯里化的特点及应用
      • 2.4.自动柯里化函数的实现
    • 3.组合函数

前言

函数式编程(Functional Programming),又称为泛函编程,是一种编程范式。早在很久以前就提出了函数式编程这个概念了,而后面一直长期被面向对象编程所统治着,最近几年函数式编程又回到了大家的视野中,JavaScript是一门以函数为第一公民的语言,必定是支持这一种编程范式的,下面就来谈谈JavaScript函数式编程中的核心概念纯函数、柯里化以及组合函数。

1.纯函数

1.1.纯函数的概念

对于纯函数的定义,维基百科中是这样描述的:在程序设计中,若函数符合以下条件,那么这个函数被称之为纯函数。

  • 此函数在相同的输入值时,需产生相同的输出
  • 函数的输入和输出值以外的其他隐藏信息或状态无关,也和由I/O设备产生的外部输出无关
  • 该函数不能有语义上可观察的函数副作用,诸如“触发事件”,使输出设备输出,或更改输出值以外物件的内容等;

对以上描述总结就是:

  • 对于相同的输入,永远会得到相同的输出;
  • 在函数的执行过程中,没有任何可观察的副作用;
  • 同时也不依赖外部环境的状态;

1.2.副作用

上面提到了一个词叫“副作用”,那么什么是副作用呢?

  • 通常我们所说的副作用大多数是指药会产生的副作用;
  • 而在计算机科学中,副作用指在执行一个函数时,除了得到函数的返回值以外,还在函数调用时产生了附加的影响,比如修改了全局变量的状态,修改了传入的参数或得到了其它的输出内容等;

1.3.纯函数案例

  • 编写一个求和的函数sum,只要我们输入了固定的值,sum函数就会给我们返回固定的结果,且不会产生任何副作用。

    function sum(a, b) {return a + b
    }const res = sum(10, 20)
    console.log(res) // 30
    
  • 以下的sum函数虽然对于固定的输入也会返回固定的输出,但是函数内部修改了全局变量message,就认定为产生了副作用,不属于纯函数。

    let message = 'hello'
    function sum(a, b) {message = 'hi'return a + b
    }
    
  • 在JavaScript中也提供了许多的内置方法,有些是纯函数,有些则不是。像操作数组的两个方法slice和splice。

    • slice方法就是一个纯函数,因为对于同一个数组固定的输入可以得到固定的输出,且没有任何副作用;

      const nums = [1, 2, 3, 4, 5]
      const newNums = nums.slice(1, 3)
      console.log(newNums) // [2, 3]
      console.log(nums) // [ 1, 2, 3, 4, 5 ]
      
    • splice方法不是一个纯函数,因为它改变了原数组nums;

      const nums = [1, 2, 3, 4, 5]
      const newNums = nums.splice(1, 3)
      console.log(newNums) // [ 2, 3, 4 ]
      console.log(nums) // [ 1, 5 ]
      

2.柯里化

2.1.柯里化的概念

对于柯里化的定义,维基百科中是这样解释的:

  • 柯里化是指把接收多个参数的函数,变成接收一个单一参数(最初函数的第一个参数)的函数,并且返回接收余下的参数,而且返回结果的新函数的技术;
  • 柯里化声称**“如果你固定某些参数,你将得到接受余下参数的一个函数”**;

总结:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数的过程就称之为柯里化。

2.2.函数柯里化的过程

编写一个普通的三值求和函数:

function sum(x, y, z) {return x + y + z
}const res = sum(10, 20, 30)
console.log(res) // 60

将以上求和函数柯里化得:

  • 将传入的三个参数进行拆解,依次返回一个函数,并传入一个参数;
  • 在保证同样功能的同时,其调用方式却发生了变化;
  • 注意:在拆解参数时,不一定非要将参数拆成一个个的,也可以拆成2+1或1+2;
function sum(x) {return function(y) {return function(z) {return x + y + z}}
}const res = sum(10)(20)(30)
console.log(res)

使用ES6箭头函数简写为:

const sum = x => y => z => x + y + z

2.3.函数柯里化的特点及应用

  • **让函数的职责更加单一。**柯里化可以实现让一个函数处理的问题尽可能的单一,而不是将一大堆逻辑交给一个函数来处理。

    • 将上面的三值求和函数增加一个需求,在计算结果之前给每个值加上2,先看看不使用柯里化的实现效果:

      function sum(x, y, z) {x = x + 2y = y + 2z = z + 2return x + y + z
      }
      
    • 柯里化的实现效果:

      function sum(x) {x = x + 2return function(y) {y = y + 2return function(z) {z = z + 2return x + y + z}}
      }
      
    • 很明显函数柯里化后,让我们对每个参数的处理更加单一

  • **提高函数参数逻辑复用。**同样使用上面的求和函数,增加另一个需求,固定第一个参数的值为10,直接看柯里化的实现效果吧,后续函数调用时第一个参数值都为10的话,就可以直接调用sum10函数了。

    function sum(x) {return function(y) {return function(z) {return x + y + z}}
    }const sum10 = sum(10) // 指定第一个参数值为10的函数
    const res = sum10(20)(30)
    console.log(res) // 60
    

2.4.自动柯里化函数的实现

function autoCurrying(fn) {// 1.拿到当前需要柯里化函数的参数个数const fnLen = fn.length// 2.定义一个柯里化之后的函数function curried_1(...args1) {// 2.1拿到当前传入参数的个数const argsLen = args1.length// 2.1.将当前传入参数个数和fn需要的参数个数进行比较if (argsLen >= fnLen) {// 如果当前传入的参数个数已经大于等于fn需要的参数个数// 直接执行fn,并在执行时绑定this,并将对应的参数数组传入return fn.apply(this, args1)} else {// 如果传入的参数不够,说明需要继续返回函数来接收参数function curried_2(...args2) {// 将参数进行合并,递归调用curried_1,直到参数达到fn需要的参数个数return curried_1.apply(this, [...args1, ...args2])}// 返回继续接收参数函数return curried_2}}// 3.将柯里化的函数返回return curried_1
}

测试:

function sum(x, y, z) {return x + y + z
}const curryingSum = autoCurrying(sum)const res1 = curryingSum(10)(20)(30)
const res2 = curryingSum(10, 20)(30)
const res3 = curryingSum(10)(20, 30)
const res4 = curryingSum(10, 20, 30)
console.log(res1) // 60
console.log(res2) // 60
console.log(res3) // 60
console.log(res4) // 60

3.组合函数

**组合函数(Compose Function)**是在JavaScript开发过程中一种对函数的使用技巧、模式。对某一个数据进行函数调用,执行两个函数,这两个函数需要依次执行,所以需要将这两个函数组合起来,自动依次调用,而这个过程就叫做函数的组合,组合形成的函数就叫做组合函数。

需求:对一个数字先进行乘法运算,再进行平方运算。

  • 一般情况下,需要先定义两个函数,然后再对其依次调用:

    function double(num) {return num * 2
    }
    function square(num) {return num ** 2
    }const duobleResult = double(10)
    const squareResult = square(duobleResult)
    console.log(squareResult) // 400
    
  • 实现一个组合函数,将duoble和square两个函数组合起来:

    function composeFn(fn1, fn2) {return function(num) {return fn2(fn1(num))}
    }const execFn = composeFn(double, square)
    const res = execFn(10)
    console.log(res) // 400
    

实现一个自动组合函数的函数:

function autoComposeFn(...fns) {// 1.拿到需要组合的函数个数const fnsLen = fns.length// 2.对传入的函数进行边界判断,所有参数必须为函数for (let i = 0; i < fnsLen; i++) {if (typeof fns[i] !== 'function') {throw TypeError('The argument passed must be a function.')}}// 3.定义一个组合之后的函数function composeFn(...args) {// 3.1.拿到第一个函数的返回值let result = fns[0].apply(this, args)// 3.1.判断传入的函数个数if (fnsLen === 1) {// 如果传入的函数个数为一个,直接将结果返回return result} else {// 如果传入的函数个数 >= 2// 依次将函数取出进行调用,将上一个函数的返回值作为参数传给下一个函数// 从第二个函数开始遍历for (let i = 1; i < fnsLen; i++) {result = fns[i].call(this, result)}// 将结果返回return result}}// 4.将组合之后的函数返回return composeFn
}

测试:

function double(num) {return num * 2
}
function square(num) {return num ** 2
}const composeFn = autoComposeFn(double, square)
const res = composeFn(10)
console.log(res) // 400

JavaScript函数式编程(纯函数、柯里化以及组合函数)相关推荐

  1. 纯函数、柯里化、组合函数的解析以及代码实现

    文章目录 一.纯函数的概念和理解 二.JavaScript柯里化 1.柯里化的理解 2.将函数柯里化的代码实现 三.组合函数 1.组合函数的理解 2.通用的组合函数的实现 一.纯函数的概念和理解 纯函 ...

  2. JS函数式编程思维:柯里化、闭包

    偏函数(Partial Application): 探讨柯里化之前,我们先聊一聊很容易跟其混淆的另一个概念--偏函数(Partial Application).在维基百科中,对 Partial App ...

  3. 从一道面试题认识函数柯里化

    最近在整理面试资源的时候,发现一道有意思的题目,所以就记录下来. 题目 如何实现 multi(2)(3)(4)=24? 首先来分析下这道题,实现一个 multi 函数并依次传入参数执行,得到最终的结果 ...

  4. scala 环境搭建 变量 值 数据类型 元组 表达式块 语句 函数 柯里化 集合 面向对象 隐式转换

    scala (scalable的简写) scala是一个比较冷门的语言,不太被人们所知道 为什么这么冷门的语言现在被我们使用 很多的大数据的项目的源码是是用scala语言编写的. 因为大数据技术不断被 ...

  5. 了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化

    js基础知识中的作用域和闭包 一.作用域 1.作用域.自由变量简介 (1)作用域定义 (2)作用域实例演示 (3)自由变量定义 (4)自由变量实例演示 2.作用域链简介 (1)作用域链定义 (2)作用 ...

  6. 什么是函数柯里化,函数柯里化的应用场景,函数柯里化的优缺点

    函数柯里化 1. 什么是函数柯里化? 2. 函数柯里化面试题 3. 应用场景 1. 什么是函数柯里化? 函数柯里化是js闭包的典型应用.所以缺点就是闭包造成的缺点,占用内存较多等 什么是函数柯里化?就 ...

  7. 带你看懂javascript函数柯里化(currying)

    1.什么是柯里化 这里参照百度百科: 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技 ...

  8. JavaScript 专题之函数柯里化

    JavaScript 专题系列第十三篇,讲解函数柯里化以及如何实现一个 curry 函数 定义 维基百科中对柯里化 (Currying) 的定义为: In mathematics and comput ...

  9. [转载] 纯函数和函数柯里化

    参考链接: 用示例编写Java柯里化Currying函数 文章目录 纯函数什么是纯函数纯函数例子非纯函数例子 函数柯里化函数柯里化简单例子参数复用 纯函数 什么是纯函数 如果函数的调用参数相同,则永远 ...

最新文章

  1. mxnet与pytorch比较 bn层
  2. Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
  3. void类型和void *的用法
  4. 物流机器人小车的运动控制与定位
  5. 第1次在Flash Builder中写程序
  6. FreeBSD下使用Blogbio写cnblogs博客
  7. android谷歌打印插件下载地址,谷歌浏览器打印插件:Print Plus
  8. 简单的在线出入库管理用哪个系统好
  9. Windows 下取消活动分区的方法
  10. 根据银行卡号查询银行卡名称
  11. 腾讯云乐固客户端加固打包上线流程
  12. 黑帽实战 | 给大家讲讲一个二类电商的大佬的故事!
  13. 英文文献阅读时,如何做笔记?
  14. HTML字体以及图标字体iconfont、Font Awesome的使用
  15. mysql编码转换搞定
  16. Xcalibur的安装及使用说明-低分辨质谱仪采集的数据
  17. 8051写一个考研/雅思用的小计时器
  18. Markdown换行操作
  19. Paddle实践:手写数字识别
  20. Hive CTE与子查询

热门文章

  1. Java:判断是否是闰年
  2. [附源码]java+ssm计算机毕业设计基于ssm的二手手机商城rk2i3(源码+程序+数据库+部署)
  3. 群发邮件邮箱哪个群发数量高?群发邮件怎么发送更高效?
  4. 双十一电竞趴,4AM联手三星玄龙骑士掀起购物狂欢
  5. excel使用vb统计分数_使用Excel选项按钮计算调查分数
  6. 中海达ihand30手簿使用说明_GPS手簿 iHand30
  7. JavaWeb数据交互前后台[Java+JSP+MySql+tomcat] 仿12306购票系统前台和后台(一)项目介绍以及需求分析
  8. java并发怎么理解_java并发的理解
  9. android仿微博头像_Android 自定义 View 集锦|自定义圆形旋转进度条,仿微博头像加载效果...
  10. i7-1065G7和i5-1035G1 对比哪个好