概念:
相同的输入永远得到相同的输出,而且没有任何可观察的副作用;
**
对比 | 纯函数 | 非纯函数 |
---|---|---|
外部依赖 | 仅依赖入参 | 可能依赖全局变量,其他方法或者条件 |
输出 | 同样的输入,一样的输出 | 可能因为不同的情况,得到结果不同 |
对外影响 | 不改变原来的入参和环境内的变量等 | 可能会改变 |
案例
/*不是纯函数,因为同样的输入,输出结果不一致*/
function a( count ){
return count + Math.random();
}
/*不是纯函数,因为外部的 arr 被修改了*/
function b( arr ){
return arr.push(1);
}
let arr = [1, 2, 3];
b(arr);
console.log(arr); //[1, 2, 3, 1]
/*不是纯函数,以为依赖了外部的 x*/
let x = 1;
function c( count ){
return count + x;
}
数组操作方法中的纯函数slice和非纯函数splice的举例
let arr = [1,2,3,4,5];
// 纯函数 //不修改原数组
console.log(arr.slice(0,3))
console.log(arr.slice(0,3))
console.log(arr.slice(0,3))
// 不纯函数 原来的数组被修改
console.log(arr.splice(0,3))
console.log(arr.splice(0,3))
console.log(arr.splice(0,3))
- 函数式编程,不会保留计算中间的结果,所以变量是不可变的(无状态的)
用处与优点:
1. 可缓存
定义:将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。
如果要实现以上功能,主要依靠 闭包 、柯里化、高阶函数let add = (a,b) => a+b;
let calc = memoize(add);
calc(10,20);//30
calc(10,20);//30 缓存
实现原理:把参数和对应的结果数据存在一个对象中,调用时判断参数对应的数据是否存在,存在就返回对应的结果数据,否则就返回计算结果。
理论有了,我们来实现一个缓存函数: ```javascript function add(a,b){ console.log(‘执行计算’); return a+b; } const resolver = (…args)=>JSON.stringify(args);//获取args 转换成json字符串 function memoize(func,resolver){ let cache = {};//缓存对象,存放参数和结果的对应关系 return (…args)=>{
}const key = resolver(...args);
if(cache[key]){ //如果key存在直接返回 对应的值
return cache[key];
}else{//不存在 则执行func的运算 并储存到key
return (cache[key] = func(...args))
}
} const memoizeAdd = memoize(add,resolver); / console.log(memoizeAdd(1,2)); console.log(memoizeAdd(1,2)); console.log(memoizeAdd(1,2)); /
第二种写法
```javascript
let memoize = function (func, content) {
let cache = Object.create(null)
content = content || this
return (...key) => {
if (!cache[key]) {
cache[key] = func.apply(content, key)
}
return cache[key]
}
}
过程分析:
- 在当前函数作用域定义了一个空对象,用于缓存运行结果
- 运用柯里化返回一个函数,返回的函数因为作用域链的原因,可以访问到
cache
- 然后判断输入参数是不是在
cache
的中。如果已经存在,直接返回cache
的内容,如果没有存在,使用函数func
对输入参数求值,然后把结果存储在cache
中。
在Vue中也有所体现
js/**
* Create a cached version of a pure function.
*/
function cached (fn) {
var cache = Object.create(null);
return (function cachedFn (str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
/**
* Capitalize a string.
*/
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
});
...
capitalize(camelizedId)
适用场景:
- 需要大量重复计算
- 大量计算并且依赖之前的结果
**
2.可测试:纯函数让测试更方便
3.并行处理: 在多线程环境下并行操作共享的内存数据很可能出现意外情况;纯函数不需要访问共享的内存数据,所以在并行环境可以任意运行纯函数(web worker)
4.纯函数不需要访问共享的内存数据,所以在并行环境下可以任意运行纯函数