Skip to content
On this page

函数式编程

纯函数是函数式编程的一个最大的前提。

  • 纯函数、副作用的内涵

  • 纯函数、非纯函数的解析

  • 从数据流的角度理解“纯”和“不纯”的本质

  • 纯函数解决了什么问题

两个概念

什么是纯函数?

同时满足两个条件:

  • 对于相同的输入,总是得到相同的输出

  • 在执行过程中没有语义上可观察的副作用

什么是副作用?

生活上的药物副作用,我们为了治疗A疾病服用某种药物,药物在缓解A疾病的症状之余,可能会导致B疾病。那么“引发B疾病”就是这个药物的副作用。

TIP

在计算机科学中,函数副作用指当调用函数时,除了返回可能的函数值之外,还对主调用函数产生附加的影响。 ——维基百科

如果一个函数除了计算之外,还对它的执行上下文、执行宿主等外部环境造成了一些其它的影响,那么这些影响就是所谓的”副作用”。

举个例子:

js
let a = 10
let b = 20
function add() {
  return a+b
}

这个函数不是纯函数。对于相同的输入,无法做到相同的输出。初次执行 add() 时,会 return 一个 30 出来,但是在全局作用域下修改:

js
a = 30  
b = 40

此时再次调用 add(),我们得到的输出就将从 30 变为 70

对于相同的输入,add() 函数给到了不同的输出。这违背了纯函数的第一条规则:对于相同的输入,总是会得到相同的输出。

这里要强调的是:“输入”指的是函数的入参

那么如何编程一个纯函数呢?只需要把“数据的输入”交给入参来做就可以了

js
let a = 10  
let b = 20

function add(a, b) {
  return a+b
}

// 30
add(a, b)   

a = 30  
b = 40

// 70
add(a, b)

简单的改造后,add 函数就能够充分满足纯函数的两个条件了:

  • 对于相同的输入,总是会得到相同的输出:对于相同的 ab 来说,它们的和总是相等的✅

  • 在执行过程中没有语义上可观察的副作用:add() 函数除了加法计算之外没有做任何事,不会对外部世界造成额外影响✅

纯和不纯的本质

“纯”的本质——有且仅有【显式数据流】。

显式概念,约束的是数据的来源(入参)和出口(返回值)。说明数据只能以入参的形式进来,并且只能以返回值的形式出去。

纯函数 ———— 输入只能够以参数形式传入,输出只能够以返回值形式传递,除了入参和返回值之外,不以任何其它形式和外界进行数据交换的函数。

纯函数的计算完全发生在函数的内部,它不会对外部资源产生任何影响,因此纯函数的并行计算总是安全的。

纯函数是高度灵活的函数,它的计算逻辑在任何上下文里都是成立的。

设计模式中,我们强调将“变与不变”分离,而纯函数强调将计算与副作用分离。

纯函数并不是为了约束而约束,而是为了追求更高的确定性;同时引导我们做更加合理的逻辑分层,写出更加清晰、更善于应对变化的代码。

一等公民

头等函数的核心特征是可以被当做变量一样用

  • 可以被当作参数传递给其他函数

  • 可以作为另一个函数的返回值

  • 可以被赋值给一个变量

JS 函数的本质,就是可执行的对象

确保数据的不可变性

“不可变”不是要消灭变化,而是要控制变化。控制变化,确保所有的变化都在可预期的范围内发生,从而防止我们的程序被变化“偷袭”。

数据不可变性如何在前端业务中落地?