在数学中,函数的概念就是,对于输入 x 产生一个输出 y=f(x) 。
纯函数的定义:对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。(纯函数是指不依赖、不修改其作用域之外变量的函数)。
eg1:反例
var num = 18;
function compare(x){
return x > num;
}
console.log(compare(20)); //true
解释:这个函数不是纯函数,因为返回值依赖外部作用域的num。
eg2:修改eg1
function compare(x, num){
return x > num;
}
console.log(compare(20, 18)); //true
解释:这个函数只与传进来的参数有关,不依赖外界,与其无关的作用域里的变量无关;同时,函数执行完毕后,没有对外界产生影响(没有修改外界的变量的值)。
eg3:接着看
var num = 18;
function compare(x, num){
//预编译时,使用的是compare函数作用域的num,依旧是纯函数
//num = 19; //代码片段1(此处不用看,在下一步与eg4对比中使用)
return x > num;
}
console.log(compare(20, num)); //true
//结论:最然传入的是全局的num,但依旧是纯函数
eg4:与eg3对比,会改变外部变量的栗子:
var arr = [];
function add(_arr){
var obj = {name: 'djl'};
_arr.push(obj);
}
add(arr);
console.log(arr); //[{name: 'djl'}],对外界变量arr产生了影响。
//结论:不是纯函数。
//【重点】因为eg3中的num是原始值,arr是引用值,arr传入的是存储地址,所以会改变外部的arr;而eg3中,即使代码片段1修改了num的值,但也不会改变外部的num.
eg5:改进eg4,使得外部变量不会改变。
var arr = [];
function add(_arr){
var obj = {name: 'djl'},
newArr = []; //新建一个数组,不改变外部数组
newArr.push(obj);
return newArr;
}
var newArr = add(arr);
eg6:进一步深入。数组中还有引用对象的情况。
var arr = [{name: 'ppy'}];
function add(_arr){
var obj = {name: 'djl'},
newArr = []; //新建一个数组,不改变外部数组
//先进行克隆外部传入的数组
for(var i = 0; i < _arr.length; i++){
newArr[i] = deepClone(_arr[i]); //此处需要你自己写的对对象的一个深度克隆函数,处理数组中存在引用值。
}
newArr.push(obj);
return newArr;
}
var newArr = add(arr);
newArr[0].name = 'haha'; //如果不使用deepClone函数,此时就会改变arr的值,而无法满足纯函数的定义。
newArr.push({name: 'hello'});
bug-守恒定律:
一旦网站或者应用的代码量达到一定的程度,他将不可避免的包含某种bug。这不是JS特有的问题,而是几乎所有语言的通病--虽然不是不可能,但是想要彻底清除程序中的所有bug还是非常难办到的。但是,这并不意味着我们不可以通过某些编码方式来预防bug的引入。
纯函数的作用:在JS中你可能很容易创建全局变量,这些变量通常可以在所有函数中访问到。这也是导致bug的一个常见原因,因为程序中的任何部分都可能修改全局变量从而导致函数行为出现异常。
纯函数非常容易进行单元测试,因为不需要考虑上下文环境,只需要考虑输入和输出。
纯函数是健壮的,改变执行次序不会对系统造成影响,因为纯函数的操作可以并行执行。
用处:数组过滤、组件化开发。更好的管理状态,达到预测性。(后期博客介绍,将持续更新)