函数式编程中有一个非常重要的概念叫做纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念。
比如:React中组件就被要就像是一个纯函数(为什么是像?是因为还有class组件),redux中有一个reducer的概念,也是要求必须是一个纯函数。所以掌握纯函数对于理解很多框架设计是非常有帮助的。
纯函数的维基百科定义:
在程序设计中,若一个函数符合以下要求,则它可能被认为是纯函数:
- 此函数在相同的输入值时,需产生相同的输出。
- 函数的输出和输入值以外的其他隐藏信息或状态无关,也和由I/O设备产生的外部输出无关。
- 该函数不能有语义上可观察的函数副作用,诸如“触发事件”,使输出设备输出,或更改输出值以外物件的内容等。
当然官方的定义会过于晦涩,所以简单总结一些:
- 确定的输入,一定会产生确定的输出;
- 函数在执行过程中,不能产生副作用;
下面是一些简单的纯函数实例:
function sum(num1, num2) {
return num1 + num2
}
sum(10,20) // 30
sum(10,20) // 30
sum(10,20) // 30
这就是一个简单地纯函数,因为在相同的输入值时(10、20)时,不会产生第二种结果,同时没有产生副作用。
我们对以上代码稍加改造一下:
var num = 100
function sum(num1, num2) {
return num1 + num2 + num
}
sum(10,20) // 130
sum(10,20) // 130
sum(10,20) // 130
第一眼看过去会让人误以为sum函数是一个纯函数,但是如果在此代码后之执行一些操作后,就会带来意想不到的后果
num = 200;
sum(10,20) // 230
sum(10,20) // 230
sum(10,20) // 230
这个时候我们依旧传入10、20会发现结果不是 130 ,而是 230 。这是因为我们这个sum函数依赖外部 num 变量而产生的“副作用”。
num = 200;
sum(10,20) // 230
sum(10,20) // 230
sum(10,20) // 230
function printInfo(info) {
console.log(info.name, info.age, info.message)
info.flag = "已经打印结束"
address = info.address
}
var obj = {
name: "why",
age: 18,
message: "哈哈哈哈"
}
printInfo(obj)
console.log(obj)
这个函数依旧不是一个纯函数,同理是因为产生了“副作用”!当我们调用printInfo时,外面的obj 已经多了一个flag属性。
需要注意的是,这些示例中的纯函数都没有修改原始数据或外部状态,而是通过返回新的结果来实现功能。它们的输出仅取决于输入,没有副作用,因此在使用时更可靠和可预测。
纯函数的关键是避免对外部状态的依赖和修改,以及确保相同的输入始终产生相同的输出。这种特性使得纯函数在函数式编程和无副作用的场景中特别有价值。