什么是纯函数?
纯函数是在调用该函数,函数执行的时候,不会修改全局变量,不依赖与全局变量,不改变其他的作用域,并且一定要返回值。总体上来说满足3个条件。
(1.有返回值(return) 2.不依赖于全局变量 3.不改变其他的作用域(GO),是利用的自己的AO(在传递参数的时候实现))
反例:
var num = 18;
function compare(x){
return x > num;
}
console.log(compare(20)); //true
解释:这个函数不是纯函数,因为返回值依赖外部作用域的num。
纯函数
function compare(x, num){
return x > num;
}
console.log(compare(20, 18)); //true
解释:这个函数只与传进来的参数有关,不依赖外界,与其无关的作用域里的变量无关;同时,函数执行完毕后,没有对外界产生影响(没有修改外界的变量的值)。
接着看
var num = 18;
function compare(x, num){
//预编译时,使用的是compare函数作用域的num,依旧是纯函数
//num = 19; //代码片段1(此处不用看,在下一步与eg4对比中使用)
return x > num;
}
console.log(compare(20, num)); //true
//结论:最然传入的是全局的num,但依旧是纯函数
作为参数传递,表面上看是传入了外部的变量,实际上函数执行使用的是自己的变量(预编译,参数),不改变外部变量的值。
会改变外部变量的栗子:
var arr = [];
function add(_arr){
var obj = {name: 'Ahua'};
_arr.push(obj);
}
add(arr);
console.log(arr); //[{name: 'Ahua'}],对外界变量arr产生了影响。
//结论:不是纯函数。
//【重点】因为eg3中的num是原始值,arr是引用值,arr传入的是存储地址,所以会改变外部的arr;而eg3中,即使代码片段1修改了num的值,但也不会改变外部的num.
var arr = [];
function add(_arr){
var obj = {name: 'Ahua'},
newArr = []; //新建一个数组,不改变外部数组
newArr.push(obj);
return newArr;
}
var newArr = add(arr);
这样改进就不会改变外边的arr了,这样就是一个纯函数了。
进一步深入。数组中还有引用对象的情况。
var arr = [{name: 'wjh'}];
function add(_arr){
var obj = {name: 'wjh'},
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的一个常见原因,因为程序中的任何部分都可能修改全局变量从而导致函数行为出现异常。
纯函数非常容易进行单元测试,因为不需要考虑上下文环境,只需要考虑输入和输出。
纯函数是健壮的,改变执行次序不会对系统造成影响,因为纯函数的操作可以并行执行。
纯函数的使用场景
1.数组过滤
<input type="text" id="inp">
<script>
var personArr = [{name : "王江华"},{name : "刘华"},{name : "王江"},{name : "王华"},{name : "刘江华"}];
var inp = document.getElementById('inp');
// console.log(inp)
inp.oninput = function () {
console.log(newArrByTest(this.value,personArr));
}
function newArrByTest (test,arr) {
let newArr = [];
for(var i = 0; i < arr.length; i ++) {
arr[i].name.indexOf(test) != -1 ? newArr.push(arr[i]) : ''; //这里需要注意的是 字符串的inedxOf(''),返回的是0 “asfest”.indexOf('') = 0
}
console.log(newArr);
return newArr;
}
2.组件化开发,状态共享 (后续会持续更新,介绍到)