用JavaScript的管道方法简化代码复杂性

用JavaScript的管道方法简化代码复杂性

在现代 web 开发中,维护干净有效的代码是必不可少的。随着项目的增加,我们功能的复杂性也在增加。然而,javaScript为我们提供了一个强大的工具,可以将这些复杂的函数分解为更小的、可管理的片段。在本文中,我们将探索使用 pipe 方法并通过一个真实的场景展示它的好处。

这是一个基本的pipe:
在这里插入图片描述

让我们从需要解决的问题开始

我们要计算用户购买各种产品时的最终价格。首先,有些产品有折扣的条件,所以我们想使用折扣对象,以便对产品的原价进行折扣计算。然后,我们要计算折扣价格的总和。如果顾客有优惠券,我们也需要考虑到这一点。最后,在以一种货币计算价格之后,将其转换成另一种货币,我们将最终价格交付给客户。

在这里插入图片描述
数据:

  • userPurchases:代表用户购买的产品清单。每件物品都有一个唯一的标识符(id)、产品名称(name)、价格 (price)、及价格的货币(currency)。
  • DISCOUNT_MAP:它将产品标识与折扣百分比联系起来。
  • COUPON_USD:客户持有的美元折扣券价值,可从总购货价格中减去。
  • USD_TO_EUR:美元兑换成欧元的兑换率保持不变。
const userPurchases = [{id: 101,price: 34.99,name: 'Wireless Headphones',currency: 'USD',},{id: 202,price: 149.95,name: 'Digital Camera Kit',currency: 'USD',},{id: 303,price: 19.99,name: 'Home Gym Equipment',currency: 'USD',},
];const DISCOUNT_MAP = new Map([[101, 10],[303, 20],[404, 30],
]);const COUPON_USD = 75;
const USD_TO_EUR = 0.94;

在我们的设想中,将执行以下步骤:

  • 根据折扣对象计算新价格。
  • 计算产品的总和。
  • 减去优惠券的。
  • 将结果从美元改为欧元。

以下是初步实施情况:

const calculateFinalPrice = (userPurchases,discountMap,userCoupon,conversionRate,
) => {//定义一个计算项目折扣价格的函数。const calculateDiscount = (price, discount = 0) => {if (discount < 0 || discount > 100) return price;if (price < 0) return NaN;return price * ((100 - discount) / 100);};//对使用折扣的物品实行折扣。const itemsWithDiscount = userPurchases.map(item => ({...item,price: calculateDiscount(item.price, discountMap.get(item.id)),}));//计算所有项目的价格总额。const total = itemsWithDiscount.reduce((acc, item) => acc + item.price, 0);//从总数中减去用户的优惠券价值。const totalAfterCoupon = total - userCoupon;//转换成一种特定的货币。const finalPrice = totalAfterCoupon * conversionRate;return finalPrice;
};

如果我们仔细看代码,就会发现我们通过以下步骤解决了这个问题:

在这里插入图片描述

这种方法有什么不好的?

我们只在一个函数中就解决了所有这些步骤。如果我们在这4个步骤中出现了一个 bug 呢?我们就必须找出我们的函数哪一部分导致了这个问题,这个过程中我们就可能需要花费大量时间去排查问题。

所以,下面让我们看看如何实现 pipe 方法来解决这个问题。

pipe 方法

pipe 方法允许我们将一个大的、复杂的函数分解为更小的、可组合的函数。

这是一个简单实现这个函数的例子:

const pipe = (...fns) => (arg) => fns.reduce((v, fn) => fn(v), arg);

这个想法很简单,将多个函数组合起来,从左到右依次应用它们,使用前一个函数的输出作为下一个函数的输入。

例如,如果我们有函数A、B和C,并且希望它们按照 A ->B -> C 流程应用于某些数据x,我们可以使用像这样使用 pipe:

const result = pipe(funcA,funcB,funcC
)(x);

以下是它的工作原理:

  • pipe 以一个或多个功能作为输入,…fns 部分意味着我们可以提供任意数量的函数,用逗号分隔,它们将被视为一个列表。
  • 它返回一个新的函数,可以接受某些输入数据,用 arg 表示。这个输入数据可以是任何东西,如数字、文本或更复杂的信息。
  • 在这个新函数中,它使用了reduce 将列表中的每个函数应用到输入数据中,一个接一个。把它看作是通过一系列的处理步骤传递输入。
  • reduce 函数负责逐步处理。从 arg 这个原始输入开始,并将列表中的第一个函数应用到列表中。然后,它获取结果并应用下一个函数,以此类推,直到它完成列表中的所有函数。
  • 最后,它返回将所有这些函数应用于输入数据的最终结果。

现在,让我们应用这些概念:

//定义一个计算项目折扣价格的函数。
const calculateDiscount = (price, discount = 0) => {if (discount < 0 || discount > 100) return price;if (price < 0) return NaN;return price * ((100 - discount) / 100);
}// 创建一个函数使用discountMap
const applyDiscounts = discountMap => items =>items.map((item) => ({...item,price: calculateDiscount(item.price, discountMap.get(item.id)),}));// 定义一个计算所有项目价格合计的函数。
const calculateTotal = items => items.reduce((total, item) => total + item.price, 0);//创建一个函数,从中减去用户的优惠券价值。
const subtractCoupon = coupon => total => total - coupon;//转换成一种特定的货币。
const convertTo = conversionRate => total => total * conversionRate;const calculateFinalPrice = (items, discountMap, coupon, conversionRate) =>pipe(applyDiscounts(discountMap),calculateTotal,subtractCoupon(coupon),convertTo(conversionRate),)(items);

我们从用户购买的数据开始,在每个步骤中,我们应用一个特定的函数并转换数据,直到我们得到最终结果。

就像这样:

在这里插入图片描述

这种办法的好处是什么?

我们已经创建了几个较小的、专门的函数来解决一个具体的问题。我们现在可以在应用程序的其他地方使用它们。我们可以分别测试每个函数。

例如,如果我们想测试折扣计算功能,我们可以这样做:

import { calculateDiscount } from './calculateDiscount';describe('calculateDiscount function', () => {it('当折扣为负数时,应退回原价。', () => {const price = 100;const discount = -10;expect(calculateDiscount(price, discount)).toBe(100);});it('当折扣为零时,应退回原价。', () => {const price = 100;const discount = 0;expect(calculateDiscount(price, discount)).toBe(100);});
});

结论

通过将复杂的流程分解为较小的可测试单元,我们可以提高代码质量,减少错误,并使我们的代码库更容易理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【 RTTI 】

RTTI 概念&#xff1a; RTTI(Run Time Type Identification)即通过运行时类型识别&#xff0c;程序能够使用基类的指针或引用来检 查着这些指针或引用所指的对象的实际派生类型。 原因&#xff1a; C是一种静态类 型语言。其数据类型是在编译期就确定的&#xff0c;不能在运…

MySQL的系统信息函数

系统信息函数让你更好的使用MySQL数据库 1、version()函数 查看MySQL系统版本信息号 select version();2、connection_id()函数 查看当前登入用户的连接次数 直接调用CONNECTION_ID()函数--不需任何参数--就可以看到当下连接MySQL服务器的连接次数&#xff0c;不同时间段该…

(数据结构)顺序表的插入删除

#include<stdio.h> #include<stdlib.h> #define MAX 10 typedef struct {int data[MAX];int lenth; }List; //初始化 void CreateList(List* L) {L->lenth 0;for (int i 0; i < MAX; i){L->data[i] 0;} } //插入 int ListInsert(List* L,int i,int e) …

ESP32-Web-Server编程- 实现 Web 登录网页

ESP32-Web-Server编程- 实现 Web 登录网页 概述 是时候实现更加安全的网页了。登录机制是最简单的控制网页访问权限的方法。 需求及功能解析 本节演示如何在 ESP32 上部署一个 Web 服务器&#xff0c;并建立登录页面的机制&#xff0c;用户可以实现登录、登出的功能&#x…

算法题-统计字符个数(Python题解)

文章目录 前言思路code 前言 先前笔试做了一道算法题&#xff0c;题目是这样子的&#xff1a;&#xff08;PS&#xff1a;不用惊讶&#xff0c;是的&#xff0c;我不打算24今年考研了&#xff0c;一是&#xff0c;当初填报的学校不是我想要去的学校&#xff08;当初想一战成硕…

【HuggingFace Transformer库学习笔记】基础组件学习:Tokenizer

基础组件——Tokenizer &#xff08;1&#xff09;模型加载 from transformers import AutoTokenizersen "弱小的我也有大梦想!" # 从HuggingFace加载&#xff0c;输入模型名称&#xff0c;即可加载对于的分词器 tokenizer AutoTokenizer.from_pretrained("m…

华为电视盒子 EC6108V9C 刷机成linux系统

场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 家里装宽带的时候会自带电视盒子&#xff0c;但是由于某些原因电视盒子没有用&#xff0c;于是就只能摆在那里吃土&#xff0c;闲来无事&#xff0c;搞一下 问题描述 提示&#xff1a;这里描述项目中遇到…

【数据结构和算法】找出叠涂元素

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 三、代码 四、复杂度分析 前言 这是力扣的2661题&#xff0c;难度为中等&#xff0c;解题方案有很多种&…

Linux 系统是如何收发网络包的?(计算机网络)

一、Linux 网络协议栈 如下是TCP/IP四层网络模型&#xff0c;实际上Linux 网络协议栈与它相似 下图是Linux 网络协议栈 二、Linux 接收网络包的流程 1.网卡是计算机里的一个硬件&#xff0c;专门负责接收和发送网络包&#xff0c;当网卡接收到一个网络包后&#xff0c;会通过…

15、 深度学习之正向传播和反向传播

上一节介绍了训练和推理的概念,这一节接着训练和推理的概念讲一下,神经网络的正向传播和反向传播。 其实单看正向传播和反向传播这两个概念,很好理解。 正向传播(Forward Propagation)是指从输入层到输出层的数据流动过程,而反向传播(Backpropagation)是指数据从输出…

国际语音群呼系统

随着海外电话营销的发展&#xff0c;越来越多的出海企业通过国际语音群呼系统打开出海营销之路。企业出海营销运营&#xff0c;选择一个安全、高效、便捷的国际语音群呼系统非常重要。 一、什么是国际语音群呼系统&#xff1f; 国际语音群呼是指通过语音的方式批量向海外用户传…

如何使用 NFTScan NFT API 在 Starknet 网络上开发 Web3 应用

Starknet 是由以色列软件公司 StarkWare 开发的免许可的第 2 层网络。Starknet 作为以太坊上的 ZK Rollup 运行&#xff0c;帮助 dApp 使用 STARK 证明以更低的交易成本实现更大的计算规模。该网络允许智能合约与区块链上部署的其他合约进行交互&#xff0c;从而提高协议之间的…

drawio画图工具的四种使用方式

1、免安装使用&#xff08;绿色版&#xff09; 这种直接下载下来直接就可以使用&#xff0c;属于绿色版&#xff08;开箱即用&#xff09;&#xff0c;适用于个人 点击下载地址 2、 安装使用 这种下载下来就需要安装才可使用&#xff0c;适用于个人 点击下载地址 3、war包…

用100ask 6ull配合 飞凌 elf1的教程进行学习的记录

启动方式 百问网 elf1: 固件 emmc-otg 串口 网络 改eth0, 网线接在右边的网口eth2上

【高效开发工具系列】驼峰下划线互转

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

大数据技术之Oozie

大数据技术之Oozie 第1章 Oozie简介 Oozie英文翻译为&#xff1a;驯象人。一个基于工作流引擎的开源框架&#xff0c;由Cloudera公司贡献给Apache&#xff0c;提供对Hadoop MapReduce、Pig Jobs的任务调度与协调。Oozie需要部署到Java Servlet容器中运行。主要用于定时调度任…

NSDT场景编辑器实现真数字孪生

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1、什么是数字孪生&#xff1f; 数字孪生是资产或系统的实时虚拟模型&#xff0c;它使用来自连…

spring boot 整合 spring security

项目结构 添加依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version><relativePath/></parent><dependency><grou…

UiPath:人工智能和重新加速增长是 2024 年的好兆头

UiPath&#xff08;NYSE&#xff1a;PATH&#xff09;重新加速增长&#xff0c;同时在销售和营销方面变得最高效&#xff0c;使其成为进入 2024 年的有吸引力的成长型股票。 UiPath 最初被归类为机器人流程自动化 (RPA) 公司&#xff0c;现在认为自己是一家人工智能驱动的自动…

MATLAB R2022b 安装

文章用于学习记录 文章目录 前言下载解压安装包总结 前言 下载解压安装包 MATLAB R2022b —— A9z3 装载(Mount) MATLAB_R2022b_Win64.iso 打开装载好的 DVD 驱动器并找到 setup&#xff0c;单击鼠标右键以管理员身份运行&#xff1a; 点击窗口右上角的 高级选项下拉框&#…