纯函数
函数f的概念就是对于输入x产生一个输出y=f(x)
纯函数是指没有任何副作用的函数,除了根据输入值计算输出值之外,什么也不做。而不纯函数则可能导致副作用。
副作用包括:
- 使全局状态改变:这里的“全局”是指函数作用域之外。
- 改变其输入参数
- 抛出异常
- 执行任何 I/O 操作
纯函数拥有许多的好处:
- 并行化:由于输出值仅依赖于输入值,所以可以并行执行任务。
- 惰性求值
- 记忆化:缓存函数结果,以便只计算一次。
var num = 18;
// 这是一个纯函数
function compare(x, num){
// 这里的num是用了函数内部的num,而不是全局作用域下的num
return x > num;
}
console.log(compare(17, num)) // false
形参传递引用类型的值也会导致副作用
var arr = [];
function add(_arr){
_arr.push({name: 'xiuluo'})
}
add(arr)
console.log(arr)
bug守恒定律
一旦你的网站或应用的代码量达到一定程度,他将不可避免包含某种bug,这不是JavaScript特有的问题,而是一个几乎所有语言都有的通病。虽然不是不可能,但是要彻底清除程序中所有的bug还是很难办到的。但是,这并不意味着我们不可以通过某些编码方式来预防bug的引入。
在JavaScript中你可以很容易创建全局变量,这些变量可以在所有函数中访问到。这也是一个导致bug的常见原因,因为程序中的任何部分都可能修改全局变量从而导致函数的行为出现异常。
纯函数非常容易进行单元测试,因为不需要考虑上下文环境,只需要考虑输入和输出。
纯函数是健壮的,改变执行次序不会对系统造成影响,因此纯函数的操作可以并行执行。
用处
更好的管理状态,使得可预测性增强,降低代码管理的难度,但是前端基本都是在和副作用打交道,所有函数都是纯函数这种愿望不可强求。
函数记忆
例:对求一个数的阶乘进行函数缓存
将函数执行结果缓存到cache数组中
var cache = []
function factorial(n){
if(cache[n]){
return cache[n]
}else{
// 0和1的阶乘等于1
if(n === 0 || n === 1){
// 来一次就缓存两个
cache[0] = 1;
cache[1] = 1;
return 1
}else{
cache[n] = n * factorial(n - 1)
return cache[n]
}
}
}
设计一个函数,对其他函数缓存
function memorize(fn){
var cache = {};
return function(){
// 标识以缓冲的函数结果
var key = arguments.length + Array.prototype.join.call(arguments);
if(cache[key]){
return cache[key]
}else{
cache[key] = fn.apply(this, arguments);
return cache[key];
}
}
}
使用
console.log(memorize(factorial)(5))
1
1
1
1
1
1
1
1
1
1