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

news2024/12/29 11:14:08

用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.coloradmin.cn/o/1276916.html

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

相关文章

什么是Anaconda

Anaconda的安装也很方便。打开这个网站Anaconda下载&#xff0c;然后安装即可。 Anaconda可以帮助我们解决团队之间合作的包依赖管理问题。在没有使用Anaconda之前&#xff0c;如果你的Python程序想让你的同事运行&#xff0c;那么你的同事可能会遇到很多包依赖问题&#xff0…

【 RTTI 】

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

2023年中国消费金融行业研究报告

第一章 行业概况 1.1 定义 中国消费金融行业&#xff0c;作为国家金融体系的重要组成部分&#xff0c;旨在为消费者提供多样化的金融产品和服务&#xff0c;以满足其消费需求。这一行业包括银行、消费金融公司、小额贷款公司等多种金融机构&#xff0c;涵盖了包括消费贷款在内…

力扣15题 三数之和 双指针算法

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三…

mysql的InnoDB存储引擎

详情请参考&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html InnoDB 是一个通用目的的存储引擎&#xff0c;它在高可用性、高性能方面做了平衡。MySQL 8.0&#xff0c;InnoDB 是默认的存储引擎。在创建表的时候&#xff0c;如果没有使用ENGIN…

1+x网络系统建设与运维(中级)-练习题

一.给设备重命名 同理可得&#xff0c;所有交换机和路由器都用一下命令配置 <Huawei>sys [Huawei]sysn LSW1 二.配置VLAN LSW1&#xff1a; [LSW1]vlan batch 10 20 [LSW1]int e0/0/1 [LSW1-Ethernet0/0/1]port link-type access [LSW1-Ethernet0/0/1]port default vlan…

用户反馈组件实现(Vue3+ElementPlus)含图片拖拽上传

用户反馈组件实现&#xff08;Vue3ElementPlus&#xff09;含图片拖拽上传 1. 页面效果1.1 正常展示1.2 鼠标悬浮1.3 表单 2. 代码部分1.2 html、ts1.2 less部分 3. 编码过程遇到的问题 1. 页面效果 1.1 正常展示 1.2 鼠标悬浮 1.3 表单 2. 代码部分 1.2 html、ts <templ…

gorm修改操作中两个update方法的小细节

在使用gorm进行修改操作时&#xff0c;修改操作中如下两个方法&#xff1a; Update() Updates() 都可以实现修改&#xff0c;根据名称可以看出Update是针对单个字段&#xff0c;而后者应该是多个。 下面是主要实际操作&#xff1a; ​​ Updates() 即&#xff0c;前者确实是…

vector是如何扩容的

vector容器扩容 vector是成倍扩容的&#xff0c;一般是2倍。 vector管理内存的成员函数 开始填值 没有填值之前&#xff0c;vector元素个数和容量大小都为0 加入一个值之后&#xff1a; 加入两个值&#xff1a;重点在加入三个值&#xff0c;此时容量变为4&#xff1a;加入第…

开源图床Qchan本地部署远程访问,轻松打造个人专属轻量级图床

文章目录 前言1. Qchan网站搭建1.1 Qchan下载和安装1.2 Qchan网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar云端设置2.2 Cpolar本地设置 3. 公网访问测试总结 前言 图床作为云存储的一项重要应用场景&#xff0c;在大量开发人员的努力下&#xff0c;已经开发出大…

优彩云采集器最新版免费下载,优彩云采集器免费

随着网络时代的发展&#xff0c;SEO&#xff08;Search Engine Optimization&#xff0c;搜索引擎优化&#xff09;已经成为网站推广和营销的关键一环。在SEO的世界里&#xff0c;原创内容的重要性愈发凸显。想要做到每天更新大量原创文章&#xff0c;并不是一件轻松的事情。优…

RocketMQ主从同步原理

一. 主从同步概述 主从同步这个概念相信大家在平时的工作中&#xff0c;多少都会听到。其目的主要是用于做一备份类操作&#xff0c;以及一些读写分离场景。比如我们常用的关系型数据库mysql&#xff0c;就有主从同步功能在。 主从同步&#xff0c;就是将主服务器上的数据同步…

接口测试基础知识

一、接口测试简介 什么是接口测试&#xff1f; 接口测试是测试系统组件间接口的一种测试&#xff0c;主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。 测试的重点&#xff1a; 检查数据的交换&#xff0c;传递和控制管理过程&#xff1b;检查系统间的相互…

人工智能对我们的生活影响有多大?

一、标题解析 本文标题为“人工智能对我们的生活影响有多大&#xff1f;”&#xff0c;这是一个典型的知乎风格SEO文案标题&#xff0c;既能够吸引读者&#xff0c;又能够体现文章的核心内容。 二、内容创作 1. 引言&#xff1a;在开头&#xff0c;我们可以简要介绍人工智能…

PVE系列-LVM安装MacOS的各个版本

PVE系列-LVM安装MacOS的各个版本 环境配置大概过程&#xff1a;详细步骤&#xff1a;1.建立安装环境和下载安装工具2. 重启后&#xff0c;执行osx-setup配置虚拟机3. 安装到硬盘&#xff0c;4.设定引导盘&#xff0c;以方便自动开机启动5.打开屏幕共享和系统VNC最后的结果 引子…

【Node.js】基础梳理 6 - MongoDB

写在最前&#xff1a;跟着视频学习只是为了在新手期快速入门。想要学习全面、进阶的知识&#xff0c;需要格外注重实战和官方技术文档&#xff0c;文档建议作为手册使用 系列文章 【Node.js】笔记整理 1 - 基础知识【Node.js】笔记整理 2 - 常用模块【Node.js】笔记整理 3 - n…

第三节:提供者、消费者、Eureka

一、 提供者 消费者&#xff08;就是个说法、定义&#xff0c;以防别人叭叭时听不懂&#xff09; 服务提供者&#xff1a;业务中被其他微服务调用的服务。&#xff08;提供接口给其他服务调用&#xff09;服务消费者&#xff1a;业务中调用其他微服务的服务。&#xff08;调用…

java基于springboot框架的中小企业人力资源管理系统的设计及实现+jsp

&#xff08;1&#xff09;员工信息管理&#xff1a;员工的基本信息&#xff0c;人员编制&#xff0c;岗位管理&#xff0c;人员流动管理&#xff08;老员工转出&#xff0c;辞职&#xff0c;退休等&#xff09;&#xff0c;职工业绩考核归公管理&#xff0c;工人工种管理。 &…

负电源电压转换-TP7660H

负电源电压转换-TP7660H 简介引脚说明典型应用电路倍压与反压的应用电路 简介 TP7660H 是一款 DC/DC 电荷泵电压反转器专用集成电路。芯片能将输入范围为 2.5V&#xff5e;11V 的电压转换成相应的-2.5V&#xff5e;-11V 的输出&#xff0c;电压转换精度可达99.9%&#xff0c;电…

【矩阵论】Chapter 2—内积空间知识点总结复习

文章目录 内积空间1 内积空间2 标准正交向量集3 Gram-Schmidt正交化方法4 正交子空间5 最小二乘问题6 正交矩阵和酉矩阵 内积空间 1 内积空间 内积空间定义 设 V V V是在数域 F F F上的向量空间&#xff0c;则 V V V到 F F F的一个代数运算记为 ( α , β ) (\alpha,\beta) (α…