0%

纯函数

什么是函数式编程?

简单来说,函数式编程是一种强调以函数使用为主的软件开发风格。

还有一点你要记住,函数式编程的目的是使用函数来抽象作用在数据之上的控制流和操作,从而在系统中消除副作用减少对状态的改变。

声明式编程

函数式编程属于声明式编程范式:这种范式会描述一系列的操作,但并不会暴露它们是如何实现的或是数据流如何传过它们

我们所熟知的 SQL 语句就是一种很典型的声明式编程,它由一个个描述查询结果应该是什么样的断言组成,对数据检索的内部机制进行了抽象

我们再来看一组代码再来对比一下命令式编程和声明式编程。

1
2
3
4
5
6
7
8
9
10
11
// 命令式方式
var array = [0, 1, 2, 3]
for(let i = 0; i < array.length; i++) {
array[i] = Math.pow(array[i], 2)
}

array; // [0, 1, 4, 9]

// 声明式方式
[0, 1, 2, 3].map(num => Math.pow(num, 2))

可以看到命令式很具体的告诉计算机如何执行某个任务。

而声明式是将程序的描述与求值分离开来。它关注如何用各种表达式来描述程序逻辑,而不一定要指明其控制流或状态关系的变化。

纯函数

纯函数是指没有副作用的函数,相同的输入有相同的输出。

1
2
3
4
var counter=0
function increment(){
return ++counter;
}

这个函数是不纯的,它读取了外部变量。这种依赖外部变量进行的计算,结果很难预测,可能在某些地方修改了counter的值,导致increment出来的值不是预期的

对于纯函数有性质:

  • 仅取决于提供的输入,而不依赖于任何在函数求值或调用间隔时可能变化的隐藏状态和外部状态
  • 不会造成超出作用域的变化,例如修改全局变量或引用传递的参数

对于相同的输入,纯函数的输出结果总是一致的,可预测的,这个也称为引用透明

引用透明

引用透明是定义一个纯函数较为正确的方法,纯度在这个意义上表示一个函数的参数和返回值之间的纯度关系,如果一个函数对于相同的输入始终产生相同的结果,我们就说它是引用透明

1
2
3
4
5
6
7
// 非引用透明
var counter = 0
function increment() {
return ++counter
}
// 引用透明
var increment = (counter) => counter + 1

不可变数据

不可变数据指的是创建后不能更改的数据,与其他语言一样,js里有一些基本类型(String,NUmber等)从本质上是不可变的,但是对象就是在任意的地方可变

例如:

1
2
3
4
5
6
7
8
9
var sortDesc = function(arr) {
return arr.sort(function(a, b) {
return a - b
})
}

var arr = [1, 3, 2]
sortDesc(arr) // [1, 2, 3]
arr // [1, 2, 3]

这段代码会导致在排序中产生副作用,原始数组arr被修改了

总结

  • 使用纯函数的代码绝不会更改或破坏全局状态,有助于提高代码的可测试性和可维护性
  • 函数式编程采用声明式的风格,易于推理,提高代码的可读性。
  • 函数式编程将函数视为积木,通过一等高阶函数来提高代码的模块化和可重用性。

内容来至于《JavaScript函数式编程指南》