我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何使用函数式TypeScript代码

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何使用函数式TypeScript代码

本篇文章给大家分享的是有关如何使用函数式TypeScript代码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

谈到函数式编程时,我们常提到机制、方法,而不是核心原则。函数式编程不是关于 Monad、Monoid 和 Zipper  这些概念的,虽然它们确实很有用。从根本上来说,函数式编程就是关于如使用通用的可复用函数进行组合编程。本文是我在重构 TypeScript  代码时使用函数式的一些思考的结果。

首先,我们需要用到以下几项技术:

  • 尽可能使用函数代替简单值

  • 数据转换过程管道化

  • 提取通用函数

来,开始吧!

假设我们有两个类,Employee 和 Department。Employee 有 name 和 salary 属性,Department 只是  Employee 的简单集合。

class Employee {   constructor(public name: string, public salary: number) {} }  class Department {   constructor(public employees: Employee[]) {}    works(employee: Employee): boolean {     return this.employees.indexOf(employee) > -1;   } }

我们要重构的是 averageSalary 函数。

function averageSalary(employees: Employee[], minSalary: number, department?: Department): number {    let total = 0;    let count = 0;     employees.forEach((e) => {      if(minSalary <= e.salary && (department === undefined || department.works(e))){        total += e.salary;        count += 1;      }    });    return total === 0 ? 0 : total / count;  }

averageSalary 函数接收 employee 数组、***薪资 minSalary 以及可选的 department 作为参数。如果传了  department 参数,函数会计算该部门中所有员工的平均薪资;若不传,则对全部员工进行计算。

该函数的使用方式如下:

describe("average salary", () => {   const empls = [     new Employee("Jim", 100),     new Employee("John", 200),     new Employee("Liz", 120),     new Employee("Penny", 30)   ];    const sales = new Department([empls[0], empls[1]]);    it("calculates the average salary", () => {     expect(averageSalary(empls, 50, sales)).toEqual(150);     expect(averageSalary(empls, 50)).toEqual(140);   }); });

需求虽简单粗暴,可就算不提代码难以拓展,其混乱是显而易见的。若新增条件,函数签名及接口就不得不发生变动,if 语句也会也越来越臃肿可怕。

我们一起用一些函数式编程的办法重构这个函数吧。

使用函数代替简单值

使用函数代替简单值看起来似乎不太直观,但这却是整理归纳代码的强大办法。在我们的例子中,这样做,意味着要将 minSalary 和 department  参数替换成两个条件检验的函数。

type Predicate = (e: Employee) => boolean;  function averageSalary(employees: Employee[], salaryCondition: Predicate,   departmentCondition?: Predicate): number {   let total = 0;   let count = 0;    employees.forEach((e) => {     if(salaryCondition(e) && (departmentCondition === undefined || departmentCondition(e))){       total += e.salary;       count += 1;     }   });    return total === 0 ? 0 : total / count; }  // ...  expect(averageSalary(empls, (e) => e.salary > 50, (e) => sales.works(e))).toEqual(150);

我们所做的就是将 salary、department  两个条件接口统一起来。而此前这两个条件是写死的,现在它们被明确定义了,并且遵循一致的接口。这次整合允许我们将所有条件作为数组传递。

function averageSalary(employees: Employee[], conditions: Predicate[]): number {   let total = 0;   let count = 0;    employees.forEach((e) => {     if(conditions.every(c => c(e))){       total += e.salary;       count += 1;     }   });   return (count === 0) ? 0 : total / count; }  //...  expect(averageSalary(empls, [(e) => e.salary > 50, (e) => sales.works(e)])).toEqual(150);

条件数组只不过是组合的条件,可以用一个简单的组合器将它们放到一起,这样看起来更加明晰。

function and(predicates: Predicate[]): Predicate {   return (e) => predicates.every(p => p(e)); }  function averageSalary(employees: Employee[], conditions: Predicate[]): number {   let total = 0;   let count = 0;    employees.forEach((e) => {     if(and(conditions)(e)){       total += e.salary;       count += 1;     }   });   return (count == 0) ? 0 : total / count; }

值得注意的是,“and” 组合器是通用的,可以复用并且还可能拓展为库。

提起结果

现在,averageSalary 函数已健壮得多了。我们可以加入新条件,无需破坏函数接口或改变函数实现。

数据转换过程管道化

函数式编程的另外一个很有用的实践是将所有数据转换过程变成管道。在本例中,就是将 filter 过程提取到循环外面。

function averageSalary(employees: Employee[], conditions: Predicate[]): number {   const filtered = employees.filter(and(conditions));    let total = 0   let count = 0    filtered.forEach((e) => {     total += e.salary;     count += 1;   });    return (count == 0) ? 0 : total / count; }

这样一来计数的 count 就没什么用了。

function averageSalary(employees: Employee[], conditions: Predicate[]): number{   const filtered = employees.filter(and(conditions));    let total = 0   filtered.forEach((e) => {     total += e.salary;   });    return (filtered.length == 0) ? 0 : total / filtered.length; }

接下来,如在叠加之前将 salary 摘取出来,求和过程就变成简单的 reduce 了。

function averageSalary(employees: Employee[], conditions: Predicate[]): number {   const filtered = employees.filter(and(conditions));   const salaries = filtered.map(e => e.salary);    const total = salaries.reduce((a,b) => a + b, 0);   return (salaries.length == 0) ? 0 : total / salaries.length; }

提取通用函数

接着我们发现,***两行代码和当前域完全没什么关系。其中不包含任何与员工、部门相关的信息。仅仅只是一个计算平均数的函数。所以也将其提取出来。

function average(nums: number[]): number {   const total = nums.reduce((a,b) => a + b, 0);   return (nums.length == 0) ? 0 : total / nums.length; }  function averageSalary(employees: Employee[], conditions: Predicate[]): number {   const filtered = employees.filter(and(conditions));   const salaries = filtered.map(e => e.salary);   return average(salaries); }

又一次,提取出的函数是完全通用的。

将所有 salary 部分提出来之后,我们得到解决方案。

function employeeSalaries(employees: Employee[], conditions: Predicate[]): number[] {   const filtered = employees.filter(and(conditions));   return filtered.map(e => e.salary); }  function averageSalary(employees: Employee[], conditions: Predicate[]): number {   return average(employeeSalaries(employees, conditions)); }

对比原始方案和***方案,我敢说,毫无疑问,后者更棒。首先,它更通用(我们可以不破坏函数接口的情况下添加新类型的判断条件)。其次,我们从可变状态(mutable  state)和 if 语句中解脱出来,这使代码更容易阅读、理解。

何时收手

函数式风格的编程中,我们会编写许多小型函数,它们接收一个集合,返回新的集合。这些函数能够以不同方式组合、复用 &mdash;&mdash;  棒极了。不过,这种风格的一个缺点是代码可能会变得过度抽象,导致难以读懂,那些函数组合在一起到底要干嘛?

我喜欢使用乐高来类比:乐高积木能够以不同形式放在一起 ;  它们是可组合的。但注意,并不是所有积木都是一小块。所以,在使用本文所述技巧进行代码重构时,千万别妄图将一切都变成接收数组、返回数组的函数。诚然,这样一些函数组合使用极度容易,可它们也会显著降低我们对程序的理解能力。

这里展示了如何使用函数式思维重构 TypeScript 代码。我所遵循的是以下几点规则:

  • 尽可能使用函数代替简单值

  • 数据转换过程管道化

  • 提取通用函数

以上就是如何使用函数式TypeScript代码,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何使用函数式TypeScript代码

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何使用 PHP 函数调试代码

php 调试函数概述:var_dump(): 显示变量的详细表示。print_r(): 输出更简洁的变量表示。xdebug: 提供高级调试功能,如设置断点和查看堆栈跟踪。如何使用 PHP 函数调试代码简介调试代码对于确保应用程序正确运行
如何使用 PHP 函数调试代码
2024-04-12

TypeScript 泛型重载函数的使用方式

这篇文章主要介绍了TypeScript 泛型重载函数的使用方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
2022-11-13

C++ 函数继承详解:如何使用虚函数实现代码复用?

函数继承允许派生类继承并重用基类的函数。通过使用虚函数,可以实现代码复用,其中派生类可以覆盖基类的同名函数,并根据调用对象类型动态执行不同的函数版本。C++ 函数继承详解:如何使用虚函数实现代码复用引言函数继承是面向对象编程 (OOP)
C++ 函数继承详解:如何使用虚函数实现代码复用?
2024-05-04

如何使用php函数来压缩和优化代码?

在开发Web应用程序时,代码的大小和效率是非常重要的。代码的大小直接影响文件的加载速度,而代码的效率则直接影响应用程序的响应时间。为了提高应用程序的性能,我们经常需要对代码进行压缩和优化。在PHP中,有一些内置的函数和方法可以帮助我们压缩和
2023-10-21

Go代码格式化gofmt如何使用

本篇内容介绍了“Go代码格式化gofmt如何使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!gofmt使用对于一门编程语言来说,代码格式化
2023-07-06

C++ 函数重载中如何使用宏来简化代码?

宏简化 c++++ 函数重载:创建宏,将通用代码提取到单个定义中。在每个重载函数中使用宏替换通用的代码部分。实际应用包括创建打印输入数据类型信息的函数,分别处理 int、double 和 string 数据类型。利用宏简化 C++ 函数重载
C++ 函数重载中如何使用宏来简化代码?
2024-04-13

如何使用 PHP 内置函数对代码进行调试?

php 内置调试函数:var_dump() 显示变量详细信息,类型、值、结构。print_r() 以更佳可读格式打印信息,适用于调试复杂数据结构。error_log() 记录消息到错误日志,方便记录调试信息、错误或警告。如何使用 PHP 内
如何使用 PHP 内置函数对代码进行调试?
2024-04-22

如何使用java函数式接口

这篇文章主要介绍了如何使用java函数式接口,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、函数式接口的由来我们知道使用Lambda表达式的前提是需要有函数式接口,而Lam
2023-06-15

excel函数公式rank如何使用

在Excel中,RANK函数用于返回一组数值中某个数值的排名。RANK函数的语法如下:RANK(number,ref,[order])- number:要计算排名的数值。- ref:包含要计算排名的数值的范围。- order:可选参数,用于
2023-09-12

PHP 函数中如何实现代码复用?

php 函数可通过组合代码块实现代码复用。函数定义包含函数名、参数和函数体。调用函数时,使用函数名和参数。命名空间可防止名称冲突。代码复用优点包括模块化、可维护性、代码简洁和效率。PHP 函数中实现代码复用PHP 函数是将代码块组合在一起
PHP 函数中如何实现代码复用?
2024-04-27

如何在 MySQL 中使用 IFNULL() 函数代替 COALESCE() 函数?

我们知道,如果第一个参数不为 NULL,IFNULL() 函数将返回第一个参数,否则返回第二个参数。另一方面,COALESCE() 函数将返回第一个非 NULL 参数。实际上,如果参数数量只有两个,MySQL 中的 IFNULL() 和 C
2023-10-22

如何使用阿里云修改数据库代码格式?

随着科技的发展,数据库的应用越来越广泛,但随之而来的是数据库代码格式的混乱,使得代码可读性降低,维护困难。阿里云提供了强大的数据库管理工具,包括数据库代码格式化功能。本文将详细介绍如何使用阿里云修改数据库代码格式。步骤一:登录阿里云首先,我们需要登录阿里云。在阿里云的管理界面中,找到“数据库管理”选项,点击进入。
如何使用阿里云修改数据库代码格式?
2023-11-01

如何使用Flex代码格式化工具

小编给大家分享一下如何使用Flex代码格式化工具,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Flex代码格式化在做Flex编码的时候,调整编码格式非常让人头疼,
2023-06-17

如何使用PyCharm进行代码格式化

PyCharm是一款强大的Python集成开发环境(IDE),其代码美化工具可以帮助开发者规范代码风格、优化代码结构,提高代码可读性。本文将介绍PyCharm代码美化工具的使用方法,并结合具体的代码示例进行详细说明。一、安装代码美化工具
如何使用PyCharm进行代码格式化
2024-02-25

如何使用代码重构技术提升 PHP 函数性能?

代码重构是提升 php 函数性能的有效技术,通过内联变量、提取方法、使用查找表等方式优化代码结构和减少重复,包括:1. 内联变量:消除变量创建和销毁开销。2. 提取方法:提高代码可读性和可维护性。3. 使用查找表:加速常量值查找。如何使用代
如何使用代码重构技术提升 PHP 函数性能?
2024-04-26

编程热搜

目录