函数式编程初探

219 阅读4分钟

为什么要学习函数式编程

函数式编程是随着 React 的流行受到越来越多的关注
Vue 3也开始拥抱函数式编程
函数式编程可以抛弃 this
打包过程中可以更好的利用 tree shaking 过滤无用代码
方便测试、方便并行处理
有很多库可以帮助我们进行函数式开发:lodash、underscore、ramda

什么是函数式编程

简单说,函数式编程"是一种“编程范式”,也就是如何编写程序的方法论。
它属于结构化编程的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式: (1 + 2) * 3 - 4
传统的编写过程

const a = 1 + 2;
const b = a * 3;
const c = b - 4;

函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样: subtract(multiply(add(1,2), 3), 4);

常用编程范式 面向过程 面向对象 函数式编程

  • 面向对象编程的思维方式:把现实世界中的事物抽象成程序世界中的类和对象,通过封装、继承和多态来演示事物事件的联系
  • 函数式编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)
  1. 相同的输入始终要得到相同的输出(纯函数)
  2. 函数式编程用来描述数据(函数)之间的映射例:y = cos(x)

函数式编程特点

函数是一等公民

MDN First-class Function

  • 函数可以存储在变量中
  • 函数作为参数
  • 函数作为返回值

只用"表达式",不用"语句"

"表达式"(expression)是一个单纯的运算过程,总是有返回值。
"语句"(statement)是执行某种操作,没有返回值。
函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

没有副作用

在计算机科学中,函数副作用指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。例如修改全局变量(函数外的变量)或修改参数。 --- 维基百科

不修改状态

函数式编程只是返回新的值,不修改系统变量

引用透明

指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。

弊端

不修改变量,意味着状态不能保存在变量中。函数式编程使用参数保存状态,最好的例子就是递归。下面的代码是一个将字符串逆序排列的函数,它演示了不同的参数如何决定了运算所处的"状态"。

function reverse(string) {
  if (string.length === 0) {
    return string;
  }
  return reverse(string.substring(1, string.length)) + string.substring(0, 1);
}

由于使用了递归,函数式语言的运行速度比较慢,这是它长期不能在业界推广的主要原因。

函数式编程意义

function memoize (fn) {
    const cache = {}
    return function() {
        const argStr = JSON.stringify(arguments)
        cache[argStr] = cache[argStr] || fn.apply(fn, arguments)
        return cache[argStr]
    }
}
  • 可缓存 (上面是手写的缓存函数)
  • 可移植
  • 可测试
  • 并行处理
  • 代码简洁,开发快速
  • 接近自然语言,易于理解
  • 更方便管理代码

函数式编程实践

高阶函数

什么是高阶函数

  • 函数作为参数
  • 函数作为另一个函数的返回结果

使用高阶函数的意义

  • 抽象可以帮我们屏蔽细节,只需要关注与我们的目标
  • 高阶函数是用来抽象通用的问题

常用的高阶函数

  • forEach
  • map
  • filter
  • every
  • some
  • find/findIndex
  • reduce
  • sort

闭包

可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员

lodash

www.lodashjs.com/

后记

函数式编程很容易写出洋葱代码,`subtract(multiply(add(1,2), 3), 4)`

image.png

如上图一样换换想扣,下一篇讲一下函数柯里化,解决这个问题。