JavaScript中的纯函数是什么?

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”:

一个函数必须通过两个测试才能被视为“纯”:

  1. Same inputs always return same outputs

    相同的输入总是返回相同的输出

  2. 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.

如果您通过24 ,则总会得到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

该测试本身是一个清单。 副作用的一些例子是

  1. Mutating your input

    改变您的输入
  2. console.log

    console.log

  3. HTTP calls (AJAX/fetch)

    HTTP调用(AJAX /提取)
  4. Changing the filesystem (fs)

    更改文件系统(fs)
  5. 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!

personshallowPersonClone都被突变了,因为他们的孩子共享相同的引用!

安全巢式变异 (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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值