JavaScript 中的纯函数和副作用是什么?

2025-06-04

JavaScript 中的纯函数和副作用是什么?

JavaScript 函数简介

函数使我们能够逻辑地放置代码来执行任务。函数Functions是 JavaScript 编程语言中的“一等公民”。您可以创建、修改函数,将其用作另一个函数的参数,或从函数中返回。您还可以将函数作为值赋给变量。简而言之,如果不使用函数,您几乎无法使用或编写任何有用的 JavaScript 代码。

在本文中,我们将了解Pure Function它的优点,并探讨Side Effects其影响。

如果您也喜欢通过视频内容学习,本文也可以作为视频教程在这里获取:🙂

请随时订阅以获取未来的内容

函数可以接受零个或多个输入并产生一个输出。你可以显式地从函数返回输出,或者它只返回一个undefined

一个函数明确返回一个值,

// Define the function
function testMe(input) {
    // Returns a string value
    return `testing ${input}`;
}

// Invoke the function
testMe(123); // returns 'testing 123'
Enter fullscreen mode Exit fullscreen mode

函数没有明确返回值,

// Define the function
function testMe() {
   // Do not return anything
}

// Invoke the function
testMe(); // returns undefined
Enter fullscreen mode Exit fullscreen mode

那么,了解了基本用法之后,让我们开始今天的Pure Function主题。我们还将理解这个概念,Side Effects以及它对纯函数的影响。

纯函数和副作用示例

作为软件程序员/开发人员,您编写源代码是为了根据输入产生输出。通常,您编写的代码functions是为了根据输入执行任务并产生输出。我们需要确保这些函数是:

  • 可预测:对于相同的输入,它可以产生可预测的输出。
  • 可读性:任何将该函数作为独立单元阅读的人都可以完全理解其用途。
  • 可重用:可以在源代码的多个地方重用该函数,而无需改变其和调用者的行为。
  • 可测试:我们可以将其作为独立单元进行测试。

APure Function具备上述所有特征。它是一个对相同输入产生相同输出的函数。这意味着传递相同的参数时,它会返回相同的结果。纯函数不应该有任何side effects改变预期输出的内容。

下面的函数sayGreeting()是一个纯函数。你能猜一下为什么吗?

function sayGreeting(name) {
  return `Hello ${name}`;
}
Enter fullscreen mode Exit fullscreen mode

它是一个纯函数,因为每次传递都会得到一个Hello <name>输出,而<name>传递的输入则为一个值。现在,我们来看一下稍有变化的相同函数。

let greeting = "Hello";

function sayGreeting(name) {
  return `${greeting} ${name}`;
}
Enter fullscreen mode Exit fullscreen mode

它是纯函数吗?嗯,不是。函数的输出现在取决于一个名为 的外部状态。如果有人将变量greeting的值更改为 ,会发生什么情况?即使传递相同的输入,函数的输出也会改变。greetingHolasayGreeting()

// When greeting is "Hello"
sayGreeting('Alex'); // Returns, "Hello Alex"

// When greeting is "Hola"
sayGreeting('Alex'); // Returns, "Hola Alex"
Enter fullscreen mode Exit fullscreen mode

因此,在这里我们看到了依赖于外部状态值的副作用,该值可能会在函数没有意识到的情况下发生变化。

一些更典型的副作用案例是,

  • 改变输入本身。
  • 查询/更新 DOM
  • 记录(即使在控制台中)
  • 进行 XHR/fetch 调用。

任何与函数最终输出不直接相关的操作都称为Side Effect。现在让我们看一个impure函数,在这个函数中,我们改变了输入,并做了一些在纯函数中不应该做的事情。

function findUser(users, item) {
    const reversedUsers = users.reverse();
    const found = reversedUsers.find((user) => {
        return user === item;
    });

    document.getElementById('user-found').innerText = found;
}
Enter fullscreen mode Exit fullscreen mode

上述函数接受两个参数:一个用户集合(一个数组)和一个要在数组中查找的项目。它通过反转数组末尾来查找该项目。一旦在数组中找到该项目,它就使用 DOM 方法将该值设置为 HTML 元素的文本。

在这里,我们违反了 的两个基本原则pure function

  1. 我们正在改变输入。
  2. 我们正在查询和操作 DOM

那么,我们可以预见什么样的问题呢?让我们看看。调用者将以findUser()以下方式调用该函数:

let users = ['Tapas', 'Alex', 'John', 'Maria'];
findUser(users, 'Maria');
Enter fullscreen mode Exit fullscreen mode

在这个阶段,除非调用者读取 findUser() 函数代码,否则调用者可能不知道该函数正在进行 DOM 操作。因此,readability函数的输出执行的操作与最终结果无关。

此外,我们还修改了输入数组。理想情况下,我们应该克隆输入,然后修改(反转)副本以用于查找操作。现在让我们将其变为一个纯函数。

function findUser(users, item) {
    // Create the clone of users array and then reverse
    const reversedUsers = [ ...users].reverse();

    // Find the element in the cloned array
    const found = reversedUsers.find((user) => {
        return user === item;
    });

    // Return the found element
    return found;
}
Enter fullscreen mode Exit fullscreen mode

然后,

let users = ['Tapas', 'Alex', 'John', 'Maria'];
let found = findUser(users, 'Maria');
Enter fullscreen mode Exit fullscreen mode

现在该findUser()函数是一个纯函数。我们消除了改变输入的副作用,并返回预期的输出。因此,该函数具有可读性、可单元测试性、可重用性和可预测性。

纯函数及相关术语

纯函数和副作用是的概念functional programming。你可能会碰到一些需要友好解释的术语。

  • 引用透明性:这意味着我们应该能够用函数的输出值替换函数调用,而不会改变程序的行为。如你所见,只有当函数是 时才有可能pure function

我们来看一个简单的纯函数,

 function multipication(x, y) {
   return x * y;
 }
Enter fullscreen mode Exit fullscreen mode

因此,现在在这个表达式中,我们可以用函数调用的输出值替换它,并保证没有side effect

  10 + (multiplication(6, 3) ^ 2);
Enter fullscreen mode Exit fullscreen mode

到,

  10 + (18 ^ 2);
Enter fullscreen mode Exit fullscreen mode
  • 并行代码:纯函数有助于并行执行代码。然而,在 JavaScript 中,代码默认是顺序运行的。

那么,我可以实现所有功能吗Pure Functions

是的,从技术上讲,你可以。但是只有纯函数的应用程序可能做不了什么。

您的应用程序可能会产生副作用,例如 HTTP 调用、控制台日志记录、IO 操作等等。请尽可能在需要的地方使用纯函数。并尽可能隔离非纯函数(副作用)。这将大大提高程序的可读性、可调试性和可测试性。

结论

拥抱函数式编程概念(例如纯函数),减少副作用将使你的代码更易于管理和维护。这意味着更少的错误、更快的问题识别和隔离,以及更高的可重用性和可测试性。

如果你想进一步探索这个主题,深入了解函数式编程,请阅读Kyle Simpson 的《Functional-Light JavaScript》。这本书值得一读。

让我们联系吧。我也在这些平台上分享我在 JavaScript、Web 开发和博客方面的学习经验。

文章来源:https://dev.to/atapas/what-are-pure-functions-and-side-effects-in-javascript-429k
PREV
深入探讨 tnpm 快速模式——我们如何做到比 pnpm 快 10 秒
NEXT
JavaScript Promises - 像我五岁一样解释