函数式编程
纯函数是函数式编程的一个最大的前提。
纯函数、副作用的内涵
纯函数、非纯函数的解析
从数据流的角度理解“纯”和“不纯”的本质
纯函数解决了什么问题
两个概念
什么是纯函数?
同时满足两个条件:
对于相同的输入,总是得到相同的输出
在执行过程中没有语义上可观察的副作用
什么是副作用?
生活上的药物副作用,我们为了治疗A疾病服用某种药物,药物在缓解A疾病的症状之余,可能会导致B疾病。那么“引发B疾病”就是这个药物的副作用。
TIP
在计算机科学中,函数副作用指当调用函数时,除了返回可能的函数值之外,还对主调用函数产生附加的影响。 ——维基百科
如果一个函数除了计算之外,还对它的执行上下文、执行宿主等外部环境造成了一些其它的影响,那么这些影响就是所谓的”副作用”。
举个例子:
let a = 10
let b = 20
function add() {
return a+b
}
这个函数不是纯函数。对于相同的输入,无法做到相同的输出。初次执行 add()
时,会 return
一个 30
出来,但是在全局作用域下修改:
a = 30
b = 40
此时再次调用 add()
,我们得到的输出就将从 30
变为 70
。
对于相同的输入,add()
函数给到了不同的输出。这违背了纯函数的第一条规则:对于相同的输入,总是会得到相同的输出。
这里要强调的是:“输入”指的是函数的入参。
那么如何编程一个纯函数呢?只需要把“数据的输入”交给入参来做就可以了
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
函数就能够充分满足纯函数的两个条件了:
对于相同的输入,总是会得到相同的输出:对于相同的
a
和b
来说,它们的和总是相等的✅在执行过程中没有语义上可观察的副作用:
add()
函数除了加法计算之外没有做任何事,不会对外部世界造成额外影响✅
纯和不纯的本质
“纯”的本质——有且仅有【显式数据流】。
显式概念,约束的是数据的来源(入参)和出口(返回值)。说明数据只能以入参的形式进来,并且只能以返回值的形式出去。
纯函数 ———— 输入只能够以参数形式传入,输出只能够以返回值形式传递,除了入参和返回值之外,不以任何其它形式和外界进行数据交换的函数。
纯函数的计算完全发生在函数的内部,它不会对外部资源产生任何影响,因此纯函数的并行计算总是安全的。
纯函数是高度灵活的函数,它的计算逻辑在任何上下文里都是成立的。
设计模式中,我们强调将“变与不变”分离,而纯函数强调将计算与副作用分离。
纯函数并不是为了约束而约束,而是为了追求更高的确定性;同时引导我们做更加合理的逻辑分层,写出更加清晰、更善于应对变化的代码。
一等公民
头等函数的核心特征是可以被当做变量一样用
可以被当作参数传递给其他函数
可以作为另一个函数的返回值
可以被赋值给一个变量
JS 函数的本质,就是可执行的对象。
确保数据的不可变性
“不可变”不是要消灭变化,而是要控制变化。控制变化,确保所有的变化都在可预期的范围内发生,从而防止我们的程序被变化“偷袭”。
数据不可变性如何在前端业务中落地?