JavaScript 函数组合:构建更易维护的代码
JavaScript 函数组合是一种将多个简单函数组合成单个更复杂函数的技术,这些函数按逻辑顺序对给定数据执行子函数操作。函数应用的顺序会产生不同的结果。
为了编写可维护的代码,理解每个被组合函数的返回类型至关重要,以确保下一个函数可以正确处理它。JavaScript 不会阻止组合返回不合适类型函数,因此这部分责任落在程序员身上。
对不熟悉函数式编程范式的人来说,组合函数可能会使代码看起来很复杂。但是,随着 ES2015 语法的出现,使用箭头函数,可以一行代码创建简单的组合函数,而无需特殊的组合方法。
组合函数应该是纯函数,这意味着每次将特定值传递给函数时,函数都应返回相同的结果,并且函数不应产生改变自身外部值的副作用。这将产生更简洁、更易读的代码。
本文由 Jeff Mott、Dan Prince 和 Sebastian Seitz 共同评审。感谢所有 SitePoint 的同行评审者,使 SitePoint 的内容达到最佳状态!
函数式思维的优势之一是能够使用小型、易于理解的单个函数来构建复杂的功能。 但有时这需要反向思考问题,而不是正向思考,以便找出如何创建最优雅的解决方案。在本文中,我将采用循序渐进的方法来检查 JavaScript 中的函数组合,并演示它如何产生更易于理解且错误更少的代码。
嵌套函数
组合是一种技术,它允许你将两个或多个简单函数组合成一个更复杂的函数,该函数按逻辑顺序对传入的任何数据执行每个子函数。要获得此结果,你需要将一个函数嵌套在另一个函数中,并对内部函数的结果重复执行外部函数的操作,直到产生结果。并且结果可能因函数应用的顺序而异。这可以使用我们已经在 JavaScript 中熟悉的编程技术轻松演示,方法是将函数调用作为参数传递给另一个函数:
function addOne(x) { return x + 1; } function timesTwo(x) { return x * 2; } console.log(addOne(timesTwo(3))); //7 console.log(timesTwo(addOne(3))); //8
在这种情况下,我们定义了一个 addOne() 函数来为一个值加 1,以及一个 timesTwo() 函数将一个值乘以 2。通过将一个函数的结果作为另一个函数的参数传入,我们可以看到如何将其中一个嵌套在另一个中会产生不同的结果,即使初始值相同也是如此。内部函数先执行,然后结果传递给外部函数。
命令式组合
如果你想重复执行相同的操作序列,定义一个新函数来自动应用第一个函数和第二个函数可能会很方便。这可能看起来像这样:
function addOne(x) { return x + 1; } function timesTwo(x) { return x * 2; } console.log(addOne(timesTwo(3))); //7 console.log(timesTwo(addOne(3))); //8
在这种情况下,我们手动将这两个函数按特定顺序组合在一起。我们创建了一个新函数,该函数首先将传递的值分配给 holder 变量,然后通过执行第一个函数,然后是第二个函数来更新该变量的值,最后返回该 holder 的值。(请注意,我们使用名为 holder 的变量来临时保存我们传入的值。对于这样一个简单的函数,额外的局部变量似乎是多余的,但即使在命令式 JavaScript 中,将传入函数的参数值视为常量也是一个好习惯。局部修改它们是可能的,但这会造成关于在函数的不同阶段调用时参数值是什么的混淆。)类似地,如果我们想创建一个另一个新函数以相反的顺序应用这两个较小的函数,我们可以执行以下操作:
// ...来自上面的先前函数定义 function addOneTimesTwo(x) { var holder = x; holder = addOne(holder); holder = timesTwo(holder); return holder; } console.log(addOneTimesTwo(3)); //8 console.log(addOneTimesTwo(4)); //10
当然,这段代码开始看起来非常重复。我们的两个新的组合函数几乎完全相同,只是它们调用的两个较小函数的执行顺序不同。我们需要简化它(就像不要重复自己一样)。此外,使用像这样改变其值的临时变量并不是很函数式,即使它隐藏在我们正在创建的组合函数内部也是如此。底线:我们可以做得更好。
创建函数式组合
让我们创建一个组合函数,它可以采用现有的函数并将它们按我们想要的顺序组合在一起。为了以一致的方式做到这一点,而无需每次都处理内部细节,我们必须决定要将函数作为参数传入的顺序。我们有两个选择。参数将分别是函数,它们可以从左到右或从右到左执行。也就是说,使用我们提出的新函数,compose(timesTwo, addOne) 可以表示 timesTwo(addOne()) 从右到左读取参数,或者 addOne(timesTwo()) 从左到右读取参数。从左到右执行参数的优点是它们将以英语相同的阅读方式读取,这与我们命名组合函数 timesTwoAddOne() 以暗示乘法应在加法之前发生的方式非常相似。我们都知道逻辑命名对于简洁易读的代码的重要性。从左到右执行参数的缺点是待操作的值必须放在前面。但是,将值放在前面使得将来用其他函数组合结果函数不太方便。为了很好地解释这种逻辑背后的思想,你无法超越 Brian Lonsdorf 的经典视频 Hey Underscore, You’re Doing it Wrong。(尽管应该注意的是,现在 Underscore 有一个 fp 选项可以帮助解决 Brian 在将 Underscore 与函数式编程库(例如 lodash-fp 或 Ramda)一起使用时讨论的函数式编程问题。)无论如何,我们真正想要做的是首先传入所有配置数据,然后最后传入要操作的值。因此,将我们的组合函数定义为读取其参数并从右到左应用它们最合乎逻辑。因此,我们可以创建一个看起来像这样的基本组合函数:
function addOne(x) { return x + 1; } function timesTwo(x) { return x * 2; } console.log(addOne(timesTwo(3))); //7 console.log(timesTwo(addOne(3))); //8
使用这个非常简单的组合函数,我们可以更简单地构建我们之前的两个复杂函数,并看到结果相同:
// ...来自上面的先前函数定义 function addOneTimesTwo(x) { var holder = x; holder = addOne(holder); holder = timesTwo(holder); return holder; } console.log(addOneTimesTwo(3)); //8 console.log(addOneTimesTwo(4)); //10
虽然这个简单的组合函数有效,但它并没有考虑许多限制其灵活性和适用性的问题。例如,我们可能想要组合两个以上的函数。此外,我们在此过程中会丢失这些信息。我们可以解决这些问题,但为了掌握组合的工作原理,这不是必需的。与其自己编写,不如从现有的函数式库(例如 Ramda)继承更强大的组合,默认情况下,它确实考虑了参数从右到左的顺序。
类型是你的责任
重要的是要记住,程序员有责任知道每个被组合函数的返回类型,以便下一个函数可以正确处理它。与执行严格类型检查的纯函数式编程语言不同,JavaScript 不会阻止你尝试组合返回不合适类型值的函数。你不仅限于传递数字,甚至不限于从一个函数到下一个函数保持相同的变量类型。但是你负责确保你正在组合的函数已准备好处理前一个函数返回的任何值。
考虑你的受众
始终记住,其他人将来可能需要使用或修改你的代码。在传统的 JavaScript 代码中使用组合对于不熟悉函数式编程范式的人来说可能会显得复杂。目标是更简洁、更易于阅读和维护的代码。但是,随着 ES2015 语法的出现,甚至可以使用箭头函数将简单的组合函数作为单行调用来创建,而无需特殊的组合方法:
function addOne(x) { return x + 1; } function timesTwo(x) { return x * 2; } console.log(addOne(timesTwo(3))); //7 console.log(timesTwo(addOne(3))); //8
今天就开始组合吧
与所有函数式编程技术一样,重要的是要记住你的组合函数应该是纯函数。简而言之,这意味着每次将特定值传递给函数时,函数都应返回相同的结果,并且函数不应产生改变自身外部值的副作用。当您有一组想要应用于数据的相关功能,并且您可以将该功能的组件分解为可重用且易于组合的函数时,组合嵌套非常方便。与所有函数式编程技术一样,我建议谨慎地将组合添加到你的现有代码中以熟悉它。如果你做对了,结果将是更简洁、更干燥、更易读的代码。难道这不是我们都想要的吗?
(以下为FAQ,已根据原文进行调整和精简,并避免重复信息)
关于函数组合和可维护代码的常见问题
-
什么是编程中的函数组合? 函数组合是将简单函数组合成更复杂函数的概念。你可以像搭积木一样,用这些小型可重用的函数创建复杂、强大的功能。这有助于使代码更易读、更易维护和更具可扩展性。
-
函数组合如何促进可维护的代码? 函数组合通过鼓励使用小型、可重用的函数来促进可维护性。这些函数更容易理解、测试和调试。当这些小型函数组合在一起以创建更复杂的功能时,更容易查明和修复可能出现的任何问题。这种模块化方法还可以更容易地更新或修改代码的某些部分,而不会影响整个系统。
-
编写可维护代码的最佳实践是什么? 编写可维护的代码涉及多项最佳实践,包括:保持函数小巧且专注于单一任务;使用有意义的变量和函数名称;对代码进行注释以解释代码逻辑背后的“原因”;遵循一致的编码风格和结构。
-
函数组合与函数式编程有何关系? 函数组合是函数式编程中的一个基本概念。函数式编程是一种将计算视为数学函数的求值并避免更改状态和可变数据的范例。在这种范例中,函数组合在从更简单的函数构建更复杂的函数中起着至关重要的作用,从而提高了代码的可重用性和可维护性。
-
实现函数组合的挑战是什么? 函数组合虽然有很多好处,但也可能带来挑战。一个挑战是,如果管理不当,它可能会导致难以阅读的代码,尤其是在组合多个函数时。在组合函数链中处理错误和异常也可能很困难。但是,可以通过良好的编码实践和正确使用函数组合来减轻这些挑战。
-
函数组合如何改进代码测试? 函数组合可以使代码测试更轻松、更高效。由于组合函数是由较小、独立的函数组成的,因此你可以单独测试每个小型函数。这使得更容易隔离和修复错误。它还促进了单元测试的实践,其中软件的每个部分都单独进行测试以确保其正常工作。
以上是功能组成:可维护代码的构建块的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

本教程向您展示了如何将自定义的Google搜索API集成到您的博客或网站中,提供了比标准WordPress主题搜索功能更精致的搜索体验。 令人惊讶的是简单!您将能够将搜索限制为Y

利用轻松的网页布局:8个基本插件 jQuery大大简化了网页布局。 本文重点介绍了简化该过程的八个功能强大的JQuery插件,对于手动网站创建特别有用

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

核心要点 JavaScript 中的 this 通常指代“拥有”该方法的对象,但具体取决于函数的调用方式。 没有当前对象时,this 指代全局对象。在 Web 浏览器中,它由 window 表示。 调用函数时,this 保持全局对象;但调用对象构造函数或其任何方法时,this 指代对象的实例。 可以使用 call()、apply() 和 bind() 等方法更改 this 的上下文。这些方法使用给定的 this 值和参数调用函数。 JavaScript 是一门优秀的编程语言。几年前,这句话可

该帖子编写了有用的作弊表,参考指南,快速食谱以及用于Android,BlackBerry和iPhone应用程序开发的代码片段。 没有开发人员应该没有他们! 触摸手势参考指南(PDF) Desig的宝贵资源

jQuery是一个很棒的JavaScript框架。但是,与任何图书馆一样,有时有必要在引擎盖下发现发生了什么。也许是因为您正在追踪一个错误,或者只是对jQuery如何实现特定UI感到好奇


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

Dreamweaver CS6
视觉化网页开发工具

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具