前言
简单来说,一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数
。
这么看可能比较抽象,把它掰开来看有已下两个特点:
- 函数的返回结果只依赖于它的参数。
- 函数执行过程里面没有副作用。
分析: 函数的返回结果只依赖于它的参数
我们首先看一个函数:
var a = 1;
function fn(b) {
return a + b;
}
console.log( fn(2) ); // 3
fn
函数不是一个纯函数,因为它返回的结果依赖于
外部变量a
,在不知道a
的值的情况下,并不能保证fn(2)
的返回值是3
。虽然fn
函数的代码实现并没有变化,传入的参数也没有变化,但它的返回值却是不可预料
的。现在fn(2)
是3
,可能过了一会就是4
或5
了,因为a
可能发生了变化变成了2
或3
了。
我们稍加改动下代码:
var a = 1;
function fn(b, c) {
return b + c;
}
console.log( fn(2, 3) ); // 5
现在
fn
的返回结果只依赖于
它的参数b
和c
,fn(1, 2)
永远是3
。今天 / 明天也是3
,在服务器 / 客户端跑3
,不管你外部发生了什么变化,fn(1, 2)
永远是3
。只要fn
代码不改变,你传入的参数是确定的,那么fn(1, 2)
的值永远是可预料
的。
以上就是纯函数的第一个条件:一个函数的返回结果只依赖于它的参数。
分析:函数执行过程里面没有副作用
一个函数执行过程对产生了外部可观察的变化那么就说这个函数是有副作用
的。
我们来看个函数:
var a = 1;
function fn(b, obj) {
return b + obj.c;
}
var tmpObj = { c: 1 }
console.log( fn(tmpObj, 2) ); // 3
console.log( tmpObj.c) ); // 1
现在
fn
可接收一个对象进行计算,计算的过程里面并不会对传入的对象进行修改,计算前后的tmpObj
不会发生任何变化,计算前是1
,计算后也是1
,所以fn
现在是纯函数。
但是我们稍微对它做下修改:
var a = 1;
function fn(b, obj) {
tmpObj.c = 2;
return b + obj.c;
}
const counter = { x: 1 }
console.log( fn(tmpObj, 2) ); // 4
console.log( tmpObj.c) ); // 2
情况发生了变化,我在
fn
内部加了一句tmpObj.c = 2
,计算前tmpObj.c
是1
,但是计算以后tmpObj.c
是2
。fn
函数的执行对外部的tmpObj
产生了影响即有了副作用
,因为它修改了外部传进来的对象,所以fn
不是纯函数了。
我们再来修改一下:
function fn(b) {
var obj = { c: 1 }
obj.c = 2
return obj.c + b
}
虽然
fn
函数内部修改了obj
,但是obj
是内部变量,外部程序根本观察不到,修改obj
并不会产生外部可观察的变化,这个函数是没有副作用
的,因此它是一个纯函数。
除了修改外部的变量,一个函数在执行过程中还有很多方式产生外部可观察的变化,比如说调用DOM API
修改页面,或者你发送了Ajax
请求,还有调用window.reload
刷新浏览器,甚至是console.log
往控制台打印数据也是副作用
。
纯函数很严格,几乎除了计算数据以外什么都不能干,计算的时候还不能依赖除了函数参数以外的数据。
总结
一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数。
为什么要煞费苦心地构建纯函数?因为纯函数非常靠谱
,执行一个纯函数你不用担心它会干什么坏事,它不会产生不可预料的行为,也不会对外部产生影响。
不管何时何地,你给它什么它就会乖乖地吐出什么。
如果你的应用程序大多数函数都是由纯函数组成,那么你的程序测试、调试起来会非常方便。
网友评论