纯函数: 相同的输入永远会得到相同的输出,而且没有任何可观察的副作用
- 函数的返回结果只依赖于它的参数
- 函数执行过程里面没有副作用。
相同的输入永远会得到相同的输出:
- 如 slice(0, 3)返回数组中的指定部分,不会改变原数组,是纯函数。
- 如 splice(0,3)多次调用, 会操作原数组并改变 每次返回的值会改变,这就不是纯函数。
let numbers = [1, 2, 3, 4, 5];
//纯函数
numbers.slice(0, 3)
// => [1, 2, 3]
numbers.slice(0, 3)
// => [1, 2, 3]
numbers.slice(0, 3)
// => [1, 2, 3]
//不纯的函数
numbers.splice(0, 3)
// => [1, 2, 3]
numbers.splice(0, 3)
// => [4, 5]
numbers.splice(0, 3)
// => []
// 不是纯函数
const a = 1;
const foo1 = (b) => x + b;
foo(2);
//纯函数
const q = 1;
const foo2 = (x, b) => x + b;
foo2(1,2)
foo1 就不是一个纯函数,他返回的结果依赖于外部变量a,返回的结果是不可预料的。
foo2 是纯函数, 因为他的返回结果 依赖于它的参数。
副作用:
例一 情况发生了变化,我在 foo 内部加了一句 obj.x = 2,计算前 counter.x 是 1,但是计算以后 counter.x 是 2。foo 函数的执行对外部的 counter 产生了影响,它产生了副作用,因为它修改了外部传进来的对象,现在它是不纯的。
例二, 但是你在函数内部构建的变量,然后进行数据的修改不是副作用
//例一
const a = 1
const foo = (obj, b) => {
obj.x = 2
return obj.x + b
}
const counter = { x: 1 }
foo(counter, 2) // => 4
counter.x // => 2
//例二
const foo = (b) => {
const obj = { x: 1 }
obj.x = 2
return obj.x + b
}
副作用来源:
- 配置文件
- 数据库
- 获取用户的输入
- …
所有外部的交互都有可能有代理副作用,副作用也使得方法通用性下降不适合扩展和可重用性,同时会给程序带来安全隐患和不确定性,但是副作用不可能完全禁止,尽可能控制他们在可控范围内发生。
总结: 一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数。
柯里化:
解决硬编码的问题
//硬编码
function checkAge(age) {
let min = 18;
return min >= age
}
//普通的函数
function checkAge(min, age) {
return min >= age
}
//柯里化
function checkAge(min) {
return function(age) {
return min >= age
}
}
const min18 = checkAge(18);
const min22 = checkAge(22);
console.log(min18(19));
console.log(min22(20));
总结:
- 柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的函数
- 这是一种对函数参数的’缓存’
- 让函数变得更灵活,让函数的粒度更小
- 可以把多元函数转换为一元函数,可以组合使用函数产生强大的功能