Pure functions are the atomic building blocks in functional programming. They are adored for their simplicity and testability.
纯函数是函数编程中的基本组成部分。 他们以其简单性和可测试性而受到赞誉。
This post covers a quick checklist to tell if a function’s pure or not.
这篇文章涵盖了一个快速核对清单,以告诉您函数是否是纯函数。
清单 (The Checklist)
A function must pass two tests to be considered “pure”:
一个函数必须通过两个测试才能被视为“纯”:
Same inputs always return same outputs
相同的输入总是返回相同的输出
- No side-effects 没有副作用
Let’s zoom in on each one.
让我们放大每个。
1.相同输入=>相同输出 (1. Same Input => Same Output)
Compare this:
比较一下:
const add = (x, y) => x + y;
add(2, 4); // 6
To this:
对此:
let x = 2;
const add = (y) => {
x += y;
};
add(4); // x === 6 (the first time)
纯函数=一致的结果 (Pure Functions = Consistent Results)
The first example returns a value based on the given parameters, regardless of where/when you call it.
第一个示例根据给定的参数返回值,无论您在何处/何时调用它。
If you pass 2
and 4
, you’ll always get 6
.
如果您通过2
和4
,则总会得到6
。
Nothing else affects the output.
没有其他影响输出。
函数不纯=结果不一致 (Impure Functions = Inconsistent Results)
The second example returns nothing. It relies on shared state to do its job by incrementing a variable outside of its own scope.
第二个示例不返回任何内容。 它依靠共享状态通过在自身作用域之外增加变量来完成其工作。
This pattern is a developer’s nightmare fuel.
这种模式是开发商梦s以求的动力。
Shared state introduces a time dependency. You get different results depending on when you called the function. The first time results in 6
, next time is 10
and so on.
共享状态引入了时间依赖性。 根据调用函数的时间,您将获得不同的结果。 第一次是6
,下次是10
,依此类推。
哪个版本更容易推理? (Which Version’s Easier to Reason About?)
Which one’s less likely to breed bugs that happen only under certain conditions?
哪一个人不太可能繁殖仅在某些条件下才会发生的错误?
Which one’s more likely to succeed in a multi-threaded environment where time dependencies can break the system?
在时间依赖性可能会破坏系统的多线程环境中,哪一个更有可能成功?
Definitely the first one.
绝对是第一个。
2.没有副作用 (2. No Side-Effects)
This test itself is a checklist. A few examples of side-effects are
该测试本身是一个清单。 副作用的一些例子是
- Mutating your input 改变您的输入
console.log
console.log
- HTTP calls (AJAX/fetch) HTTP调用(AJAX /提取)
- Changing the filesystem (fs) 更改文件系统(fs)
- Querying the DOM 查询DOM
Basically any work a function performs that isn’t related to calculating the final output.
基本上,函数执行的任何与计算最终输出无关的工作。
Here’s an impure function with a side-effect.
这是一个带有副作用的不纯函数。
还不错 (Not So Bad)
const impureDouble = (x) => {
console.log('doubling', x);
return x * 2;
};
const result = impureDouble(4);
console.log({ result });
console.log
is the side-effect here but, in all practicality, it won’t harm us. We’ll still get the same outputs, given the same inputs.
console.log
是这里的副作用,但实际上,它不会损害我们。 给定相同的输入,我们仍将获得相同的输出。
This, however, may cause a problem.
但是, 这可能会引起问题。
“不正确地”更改对象 (“Impurely” Changing an Object)
const impureAssoc = (key, value, object) => {
object[key] = value;
};
const person = {
name: 'Bobo'
};
const result = impureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
The variable, person
, has been forever changed because our function introduced an assignment statement.
因为我们的函数引入了赋值语句,所以变量person
一直被更改。
Shared state means impureAssoc
's impact isn’t fully obvious anymore. Understanding its effect on a system now involves tracking down every variable it’s ever touched and knowing their histories.
共享状态意味着impureAssoc
的影响不再完全明显。 了解其对系统的影响现在涉及到跟踪它曾经接触过的每个变量并了解其历史。
Shared state = timing dependencies.
共享状态=时序依赖性。
We can purify impureAssoc
by simply returning a new object with our desired properties.
我们可以通过简单地返回具有所需属性的新对象来净化impureAssoc
。
净化它 (Purifying It Up)
const pureAssoc = (key, value, object) => ({
...object,
[key]: value
});
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Now pureAssoc
returns a testable result and we’ll never worry if it quietly mutated something elsewhere.
现在pureAssoc
返回一个可测试的结果,我们永远pureAssoc
担心它是否会在其他地方悄悄地进行突变。
You could even do the following and remain pure:
您甚至可以执行以下操作并保持纯净:
另一种纯净的方式 (Another Pure Way)
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
});
Mutating your input can be dangerous, but mutating a copy of it is no problem. Our end result is still a testable, predictable function that works no matter where/when you call it.
更改您的输入可能很危险,但是更改其副本则没有问题。 我们的最终结果仍然是一个可测试的,可预测的函数,无论您在何处/何时调用它,它都可以工作。
The mutation’s limited to that small scope and you’re still returning a value.
变异仅限于较小的范围,并且您仍在返回值。
深克隆对象 (Deep-Cloning Objects)
Heads up! Using the spread operator ...
creates a shallow copy of an object. Shallow copies aren’t safe from nested mutations.
小心! 使用散布运算符...
创建对象的浅表副本。 浅拷贝对于嵌套突变并不安全。
Thank you Rodrigo Fernández Díaz for bringing this to my attention!
感谢RodrigoFernándezDíaz引起我的注意!
不安全的嵌套变异 (Unsafe Nested Mutation)
const person = {
name: 'Bobo',
address: { street: 'Main Street', number: 123 }
};
const shallowPersonClone = { ...person };
shallowPersonClone.address.number = 456;
console.log({ person, shallowPersonClone });
Both person
and shallowPersonClone
were mutated because their children share the same reference!
person
和shallowPersonClone
都被突变了,因为他们的孩子共享相同的引用!
安全巢式变异 (Safe Nested Mutation)
To safely mutate nested properties, we need a deep clone.
为了安全地更改嵌套属性,我们需要一个深层克隆。
const person = {
name: 'Bobo',
address: { street: 'Main Street', number: 123 }
};
const deepPersonClone = JSON.parse(JSON.stringify(person));
deepPersonClone.address.number = 456;
console.log({ person, deepPersonClone });
Now you’re guaranteed safety because they’re truly two separate entities!
现在,您将得到安全保证,因为它们实际上是两个单独的实体!
摘要 (Summary)
- A function’s pure if it’s free from side-effects and returns the same output, given the same input. 如果函数没有副作用,并且在给定相同输入的情况下返回相同的输出,则该函数是纯函数。
- Side-effects include: mutating input, HTTP calls, writing to disk, printing to the screen. 副作用包括:更改输入,HTTP调用,写入磁盘,在屏幕上打印。
You can safely clone, then mutate, your input. Just leave the original one untouched.
您可以安全地克隆您的输入, 然后对其进行 变异 。 只需保留原始的一个。
Spread syntax (
…
syntax) is the easiest way to shallowly clone objects.传播语法(
…
语法)是浅克隆对象的最简单方法。JSON.parse(JSON.stringify(object))
is the easiest way to deeply clone objects. Thanks again Rodrigo Fernández Díaz!JSON.parse(JSON.stringify(object))
是深度克隆对象的最简单方法。 再次感谢RodrigoFernándezDíaz !
我的免费课程 (My Free Course)
This tutorial was from my completely free course on Educative.io, Functional Programming Patterns With RamdaJS!
本教程来自我完全免费的课程 Educative.io, RamdaJS函数编程模式 !
Please consider taking/sharing it if you enjoyed this content.
如果您喜欢此内容,请考虑将其共享。
It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.
它包含所有课程,图形,练习和可运行的代码示例,以教您使用RamdaJS的基本功能编程样式。
Thanks for reading! Until next time.
谢谢阅读! 直到下一次。
翻译自: https://www.freecodecamp.org/news/what-is-a-pure-function-in-javascript-acb887375dfe/