写在文章前
函数式编程第四话~ 上次介绍了共享状态,这次我们谈一下他和纯函数之间的关系。
文章如果有什么不对的地方欢迎在评论区批评指正。谢谢各位看官老爷~
公共状态与函数式编程那些不能说的事
n久以前说到函数式编程的几个要点:
- 不能依赖除了入参以外的其他任何变量
- 必须要有确定的单一的返回值
那这和上次的共享状态有什么关系呢?
不能依赖除了入参以外的其他任何变量,必须要有单一确定的返回值
就意味着纯函数不能依赖于任何共享状态,一旦有依赖其他的状态或者变量的时候,就说明了,这个函数会产生副作用。
副作用
什么是副作用?副作用就是函数内部与外部有互动,这就包括:
- 依赖其他的共享装填或者变量
- 在内存中有写入的操作
- 打印到控制台,读取用户输入
- 调用了其他非纯函数
- 发起了请求
说白了就是改变了计算机的状态,服务器的状态,函数的状态都不行。读到这你可能会说:啥?请求不让发?有毒?当然,不是这样的,我们在必要的情况下,如果为了让我们的项目可用,他必须要产生的副作用并且你也知道产生作用的后果的话,我们允许他的产生。否则,一旦不确定或者压根没办法检测的副作用,我们还是要尽量杜绝他的产生。
我们不得不承认,一个有用的项目或者程序是不可能是100% 的纯函数的。函数式编程的目标不是完全杜绝副作用的产生,而是要利用某些易于管理的副作用的小部分代码,保证整个程序的可读性和可维护性。
我们可以用一个花里胡哨的词来形容我们的这种目标:引用透明性。
引用透明性
函数如果不依赖外部变量或者状态,只依赖输入的参数,就是引用透明的。我们如果能使用唯一的值来替换调用的函数表达式并且不改变程序运行状态,就证明这个函数是引用透明的。
说了一大堆,总结一下就是引用透明的函数必须是纯函数
举个栗子:
const getQQEmail = qqNo => {
console.log('user info');
return `${qqNo}@qq.com`
}
const getUserInfo = user => {
return {
no: user.no,
email: getQQEmail(user.no)
}
}
getUserInfo({
no: '23423423'
address: 'china'
})
看起来getUserInfo貌似只依赖user,也有确定的唯一返回值。我们也能替换getUserInfo的email:
const getUserInfo = user => {
return {
no: user.no,
email: `${qqNo}@qq.com`
}
}
但这改变了程序,他没有了console。(这个console是一个副作用)这也说明了getQQEmail不是引用透明的。
总结
截止到第四节为止,我们知道了什么是共享状态,引用透明,不可变性,副作用这些名词,我们也知道了怎么产生副作用,什么样子的函数是引用不透明的。那接下来我们就要真的开始了解函数式变成了,包括什么是科里化,什么是闭包之类的。