- 原文地址:medium.freecodecamp.org/what-is-a-p…
- 原文做者:Yazeed Bzadough
- Markdown 地址:github.com/wanghaiqion…
纯函数是程序函数式编程语言中原子构建块(最简单的可重用代码构建块)。简单和易测试性的特色使其备受推崇。javascript
本文将提供一个快速检测列表,用于判断一个函数是否为纯函数。java
一个函数必须知足以下两点才能被称之为“纯的”:git
让咱们逐一展开。github
比较以下两版代码:编程
const add = (x, y) => x + y;
add(2, 4); // 6
复制代码
let x = 2;
const add = (y) => {
x += y;
};
add(4); // x === 6 (the first time)
复制代码
无论你在什么时候何地调用第一个例子中的函数,获得的结果仅仅依赖于传入的参数。多线程
如传入 2
和 4
,获得结果 6
。编程语言
输出不受其余任何因素影响。函数式编程
第二个例子中的函数什么也不返回。它的工做依赖于 共享状态,递增了一个外部变量。函数
这样的话就是开发者的噩梦了。测试
共享状态 具备时序依赖性。在不一样的时机调用,会获得不同的结果。第一次获得的结果是 6
,第二次是 10
以此类推。
哪一种方式更不容易产生 bug,尤为是在某些特定条件下?
哪一种方式更能胜任多线程系统环境,尤为是这种系统环境会受时序因素影响?
显然是第一种。
这一检测点自己也是一个检测列表。以下是一些反作用:
基本上函数中执行的任何操做都与最终计算输入结果无关,仅仅依赖于传入的参数。
推荐你们看看 Uncle Bob Martin 对于系统状态问题的讲解视频。大约从 15min 处开始。
以下是产生了反作用的不纯函数。
const impureDouble = (x) => {
console.log('doubling', x);
return x * 2;
};
const result = impureDouble(4);
console.log({ result });
复制代码
虽然说 console.log
产生了反作用,但实际上它没什么不良影响。咱们仍然能保证相同的输入获得相同的输出。
然而接下来这个就不同了,可能会致使一些问题。
const impureAssoc = (key, value, object) => {
object[key] = value;
};
const person = {
name: 'Bobo'
};
const result = impureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
复制代码
函数中的赋值语句,已经让变量 person
发生了不可逆的改变。
共享状态意味着 impureAssoc
的影响不那么明显。要理解它对系统产生的反作用,需跟踪它涉及到的每个变量,了解这些变量的历史变化轨迹。
把 impureAssoc
变纯很简单,咱们只要返回一个包含所需属性的新对象便可。
const pureAssoc = (key, value, object) => ({
...object,
[key]: value
});
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
复制代码
如今 pureAssco
返回一个明确可测试的结果,再也不担忧它会在其余地方偷偷地变了。
想将它变纯,你甚至能够以下这么作:
const pureAssoc = (key, value, object) => {
const newObject = { ...object };
newObject[key] = value;
return newObject;
};
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
复制代码
直接更改函数的输入是有些风险的,但改变输入的副本就没什么问题了。无论在哪里调用,咱们都将获得一个稳定可测试的函数。