如何像高级 JavaScript 开发人员一样为一般流程编写高阶函数

网站建设4年前发布
26 0 0

20230305204713947c185359868b04c07259b38f6ec97e860c08690,一些编码人员可能会直接更改原始功能以达到某种目的。嗯,这是初级开发人员常用的方法,也是一种直观的方法。,但在很多情况下,它并不是最好的解决方案,并且有一些缺点。在今天的内容中,我将通过示例为您介绍一些通用的解决方案。,很多时候,我们想要一个只执行一次的函数。,比如,我们开发网页的时候,总会有一些提交表单的按钮。当用户点击按钮时,会触发它的 onclick 事件。,为了简化演示问题,该示例仅记录一条消息,而不是向服务器发送数据。,但这里有一个问题:由于网络延迟,我们无法立即为用户显示结果。然后用户可能继续点击该按钮并多次向服务器提交表单。,202303052047146893a33673205d0ac134533229ac571d020747703,所以,我们需要解决这个问题,你的解决方案是什么?,一个常见的解决方案是在用户第一次单击按钮后禁用该按钮。,2023030520505724047395743d334e030269d61bb7a0f36cb3e1244,嗯,这个解决方案没有问题。,另外,我们有一个不同的解决方案:,在这个解决方案中,我们使用一个标志来记录该函数之前是否已执行过。,2023030520471523ac3d7221bc3ebdd6b64298f07369680d4faf224,如果我们使用图表来表示程序,它可能是这样的:,2023030520471672b8e5f182e08317fd4204cc5e1e9b504660b2148,但是,我们能否为所有此类问题找到一个通用的解决方案?,让我们继续一个类似的例子。很多时候,我们的程序中有一个init函数。,可以使用这个函数来设置变量、读取配置等。这个函数应该只执行一次。为了确保它只执行一次并避免意外,我们可以对函数进行一些更改:,我们可以使用这个函数来设置变量、读取配置等。这个函数应该只执行一次。为了确保它只执行一次并避免意外,我们可以对函数进行一些更改:,好的,init函数只会初始化环境一次。,20230305214201998645c63cf45139c2c362f25e8ab79ea7a684259,我们还可以将程序绘制成图表。,20230305204717e9ad9b84694927ccec1777b99def88f2f37ec4468,你发现表单提交和初始化函数有一些共同点吗?是的,他们的程序非常相似!,如果我们做高级抽象,流程应该是这样的:,2023030521424334e3ca6773c1a09ee968640546e1af603db2d1119,如果该函数之前已被调用是一般程序。我们可以编写一个高阶函数来密封这个过程。,这是一次函数的实现:,现在,使用 once 函数,我们可以轻松地归档执行一次函数的目的。,提交一次:,20230305204718f80c5709931e740b00e751d78b976eeb5984b7825,初始化一次:,2023030520471813d0f13835afdd0545c9514c1d024a9ac56397135,好的,我们使用 once 函数来解决我们的需求。,使用 once 函数的核心思想是什么?,正如我在标题中提到的:我们将一般过程抽象为高阶函数。程序——只执行一次函数——是一个通用过程。它会被多次使用。如果我们不做抽象,我们就必须在不同的函数中为相同的逻辑重复编写代码。,如果我们使用 once 函数,有很多好处:,让我们来看另一个例子。,如果有这样的一个功能:,(其实这个案例我是从 Vue 源码中学到的。),我们要缓存函数操作的结果。稍后调用时,如果参数相同,则不再执行该函数,而是直接返回缓存中的结果。我们能做什么?,这里有一个建议:当你需要增强一个函数时,不要试图直接修改它,考虑先写一个通用的高阶函数来包装它。,缓存函数结果的一般过程是什么?这是一个流程:,202303052143400746b79266f0ce627b57406ce471202331237c941,这是缓存结果的实现:,现在我们可以使用这个缓存函数来增强 cumpute 函数:,20230305204719a92b1903800a4c6830f107f9ddb1555360846a849,我们做这个抽象并不是为了炫耀技巧,其实这样的缓存功能用途广泛。,我们知道,有一个著名的序列叫做斐波那契数列。,快速浏览后,您可以很容易地注意到序列的模式是每个值都是前 2 个值的总和,这意味着对于 N=5 → 2+3 或在数学中:,现在我们要写一个函数:,给定一个数字N返回斐波那契数列的索引值。,怎么写函数?,最简单的解决方案是递归解决方案:,但是这个实现很耗时,如果 num 大于 35,您将等待一段时间才能得到结果。,20230305204720214fb4a50484917c411883f62c3d1a9306b94e627,但是如果我们使用缓存函数来重构实现,我们会得到一个高性能的函数。,20230305214440f9de3cb78da8a57b5a08880de791965841a323657,让我们继续。,假设您是一个库的维护者,并且您将在未来弃用一个名为 request 的旧 API。,在当前版本中,您希望通过记录消息来警告用户 API 将被弃用。,那你会怎么做?,最糟糕的方法是在函数中添加一个 console.warn 语句:,为什么这是最糟糕的解决方案?,您必须找到所有已弃用的 API 并对其进行修改。这是一个非常繁琐的过程,而且很容易导致错误。如果没有必要,不要更改现有功能。,如果我们用图来表示程序,那就是:,20230305204721f59f70d8308228e2002306bc996291142df55b363,正如我们在前面内容中所做的那样,我们可以为该过程编写一个高阶函数。,然后我们可以对我们的项目做一些改变:,,如果您的库的用户调用请求函数,他们将收到一条消息。,好的,让我们继续一个类似的例子。,我们有一个 fetch 函数来向服务器发送请求。它将返回 HTML 文本或 JSON 格式的文本。,我们现在要做的是,如果我们发现响应结果是 JSON 格式的字符串,我们将其转换为 JSON 对象。如果是其他格式的字符串,则不进行处理。我应该怎么办?,老规矩,先画个图:,2023030520505957c74530015c05196bf324b48eb001bd610f82706,具体原理已经解释过很多次了,这里我直接给出一个高阶函数:,用法:,20230305214541a98617e8873be29a53d548259bddb8416c7e46426,这两个例子有点简单。但附近还有一个更重要的想法。,2023030520472317de41c84e3b228494d216eaa4492696d3a651125,我们能把这个过程抽象成一个新的高阶函数吗?,我们当然可以。,如果你之前用过 Axios 这个著名的 HTTP 请求库,你就会知道 Axios 有一个拦截器 API 供用户拦截请求和响应。,好的,这是我们的最后一个例子。,这是一个将输入加倍的函数。,嗯,很简单的功能,只是为了演示。,如果我们想让这个函数接受一个数组作为参数,那么将数组中所有元素的值加倍,然后返回一个新数组。你怎么写代码?,我们可以这样写:,确实可以这样写。,但遗憾的是,JavaScript 没有函数重载,后者的函数会覆盖前者。为了让我们的double函数同时处理两种参数类型,我们必须在函数体中做出判断:,我们想要的是为所有这些问题创建一个通用的解决方案:一个高阶函数,可以标记一个函数来处理单个参数或类似数组的参数。,20230305204723a25f3c962cadcec54d4042d85cabd96f7b9f20307,这是一个实现:,2023030520472394f3f8406013d4fd7449348a81119a08352f92874,我想,我举的例子已经够多了。无论是once,cache,intercept还是batch,它们都对某个进程进行了一些抽象。,Nested,恩,我想提的最后一件事:如果有必要,我们可以嵌套这些高阶函数。,20230305214640264fb3607753b150eb8537bd2193ece37e3495565,假设我们不仅要缓存计算函数的结果,还要在执行它之前记录它的参数,并在执行它之后记录它的结果。然后,我们还想让它能够处理多重参数。我们可以这样写:,

© 版权声明

相关文章