【前端,TypeScript】TypeScript速成(六):函数

函数

函数的定义

定义一个最简单的加法函数:

function add(a: number, b: number): number {return a + b
}

(可以看到 JavaScript/TypeScript 的语法与 Golang 也非常的相似)

调用该函数:

console.log(add(2, 3))
// out
[LOG]: 5

可选参数、默认参数和可变参数列表

在函数定义时,假定我们有一个可选的参数,可以在形参列表该参数后加上?。注意可选参数和默认参数一样都应该放在参数列表的后面:

function add(a: number, b: number, c?: number, d: number = 0): number {return a + b + (c || 0) + d
}console.log(add(2, 3))
console.log(add(2, 3, 9))
console.log(add(2, 3, 9, 15))
// out
[LOG]: 5 
[LOG]: 14 
[LOG]: 29

还可以加入一个可变参数列表:

function add(a: number, b: number, c?: number, d: number = 0,...e: number[]): number {let sum = a + b + (c || 0) + dfor(let i = 0; i < e.length; i ++) {sum += e[i]}return sum
}console.log(add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
// out
[LOG]: 55 

函数的重载

TypeScript 支持函数的重载(Golang 不允许函数的重载),但是不建议使用。

对象类型参数

假设我们现在有下述的函数定义:

function sendRequest(url: string, method: 'GET' | 'POST' | 'PUT',header: object,data: string,requireAuth: boolean,retry: boolean,retryTimeOut: number) {// ... ... ...
}

函数掉调用者在使用这个函数的时候,可能会给出非常冗长的参数列表,且我们无法从参数列表得知这个函数在做什么。

TypeScript 的一个解决办法是使用对象类型参数:

function sendRequest(params: {url: string, method: 'GET' | 'POST' | 'PUT',header: object,data: string,requireAuth: boolean,retry: boolean,retryTimeOut?: number,}) {// ... ... ...
}

参数直接是一个对象。函数调用时:

sendRequest({url: 'https://www.test.com',method: 'GET',header: {contentType: '... ... ...'},data: '{}',requireAuth: true,retry: true,retryTimeOut: 3000
})

这种做法使得函数调用者非常的方便。

通过函数为对象定义方法

将函数定义在对象内部,即可完成对象方法的定义:

const emp1 = {name: 'John',salary: 8000,performance : 3.5,bonus: undefined as (number | undefined),updataBonus() {if(!emp1.bonus) {emp1.bonus = emp1.salary * emp1.performance}},
}emp1.updataBonus()
console.log(emp1)// out
[LOG]: {"name": "John","salary": 8000,"performance": 3.5,"bonus": 28000
} 

观察对象方法的定义:

updataBonus() {if(!emp1.bonus) {emp1.bonus = emp1.salary * emp1.performance}
}

我们看到,必须通过 emp1 才能访问 bonus,但如果我们使用 emp2、emp3 来保存对象该怎么办呢?可以通过使用保留的关键字 this 来解决上述问题,修改后的方法如下:

updataBonus() {if(!this.bonus) {this.bonus = this.salary * this.performance}
}

函数式编程

函数式编程是 TypeScript/JavaScript 非常大的一个亮点,这个特性非常适配于前端开发。TypeScript/JavaScript 的 Promise 也是基于函数式编程的。

使用函数式编程辅助数组的排序

之前在对数组的学习过程当中我们提到过,直接对 number 类型的数组使用 sort 方法之后,数组将按照字典顺序排序,而不是按照数字大小的顺序排序。现在我们希望借助函数实现按照 number 大小进行排序:

function compareNumber(a: number, b: number) {// a < b -> 返回负数// a === b -> 返回 0// a > b -> 返回正数return a - b
}let a = [5, 2, 1, 6, 8, 10, 5, 25, 16, 23, 11]
a.sort(compareNumber)
console.log(a)

👆将函数名称传递给函数,就是函数式编程。(看起来和 C++ 当中的函数指针非常的像,但函数式编程比函数指针复杂很多,唯一和函数指针相似的地方就是在上述例子当中)

在函数式编程中,函数是一等公民

函数作为一等公民时:

  • 变量类型可以是函数;
  • 值(literal)可以是函数;
  • 对象的字段可以是函数;
  • 函数的参数也可以是函数;
  • 函数的返回值可以是函数。

变量类型可以是函数

上述的 compareNumber 函数的另一种定义形式如下:

const compareNumber = function(a: number, b: number) {return a - b
}

此时,compareNumber 是一个对象,它的类型是函数。

值(literal)可以是函数

上述 compareNumber 可以是一个变量,并被赋予其它的值(其它函数):

let compareNumber = function(a: number, b: number) {return a - b
}
compareNumber = function(a: number, b: number) {return b - a
}	// 实现降序排序

对象的字段也可以是函数

一个例子如下:

const emp1 = {name: 'John',salary: 8000,increaseSalary: function(p: number) {	// 此处不能使用箭头函数this.salary *= p					// 箭头函数和 this 之间有坑}
}

函数的参数可以是函数

比如 sort 的参数是 compareNumber。

函数的返回值可以是参数

一个例子如下:

function createComparer(greater: boolean = false) {return greater ? (a: number, b: number) => b - a : (a: number, b: number) => a - b
}let a = [5, 2, 1, 6, 8, 10, 5, 25, 16, 23, 11]
a.sort(createComparer())
console.log(a)

lambda 表达式

上述 compareNumber 函数更简单的写法如下:

let compareNumber = (a: number, b: number) => a - b

它是 lambda 表达式,在 TypeScript / JavaScript 中也被称为箭头函数。

一个快速实现排序的方法是:

a.sort((a: number, b: number) => a - b)

=>后面可以像函数体一样使用{ ... }包裹,但此时必须有返回值。

高阶函数

高阶函数指的就是返回值是函数的函数,这个概念类似于函数的叠加与嵌套。一个例子如下:

function loggingComparer(comp: (a: number, b: number) => number) {return (a: number, b: number) => {  // 对作为参数的函数进行包装console.log('comparing', a, b)  // 首先打印 logreturn comp(a, b)               // 再调用作为参数传入的函数}                                   // 看起来很像 Python 的 decorator
}

函数的闭包

在上述高阶函数 loggingComparer 的基础上,我们希望知道排序函数总共进行了多少次比较操作。可以通过函数的闭包(而不是设置全局变量)来实现上述功能。(使用全局变量的缺点在于全局变量或对象的状态字段需要维护,此外,打印同样改变了前端 UI 元素的状态,它同样也是一个副作用,我们应该尽可能地减少副作用,以提高用户体验)

一个函数闭包的例子如下,在下述代码片段中,函数 processArray 当中的局部函数 logger 和变量 compCount 是一个闭包,compCount 是它所携带的自由变量:

function loggingComparer(logger: (a: number, b: number) => void, comp: (a: number, b: number) => number) {return (a: number, b: number) => {  logger(a, b)  return comp(a, b)               }                                   
}function createComparer(params: {greater: boolean}) {return params.greater ? (a: number, b: number) => b - a : (a: number, b: number) => a - b
}let compareNumber = (a: number, b: number) => a - bfunction processArray(a: number[]) {let compCount = 0const logger = (a: number, b: number) => {console.log('comparing', a, b)compCount ++	}const comp = createComparer({greater: false})a.sort(loggingComparer(logger, comp))return compCount
}let a = [5, 2, 1, 6, 8, 10, 5, 25, 16, 23, 11]const compCount = processArray(a)
console.log(a)
console.log('Compare Count: ', compCount)

在上述例子中,随着 processArray 函数调用的结束,logger 函数也随之结束,compCount 作为返回值返回。但是如果 processArray 函数调用结束时,其内部的闭包由于某种原因尚未停止运行(比如一个线程),那么其所携带的自由变量的生命周期将会超越该函数的局部作用域。

部分应用函数

基于闭包可以实现部分应用函数。

一个部分应用的例子如下:

const a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(a.filter((v) => v % 2 == 0))
// out
[LOG]: [2, 4, 6, 8] 

一个等价的实现如下:

function isGoodNumber(goodFactor: number, v: number) {return v % goodFactor === 0
}function filterArray(a: number[], f: (v: number) => boolean) {return a.filter(f)
}const GOOD_FATOR = 2const a = [1, 2, 3, 4, 5, 6, 7, 8, 9]console.log(filterArray(a, (v) => isGoodNumber(GOOD_FATOR, v)))

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

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

相关文章

Easy-Trans反向翻译+Excel导入最佳实践

1、概述 实现用户excel上传、解析、对于用户输入的中文翻译为字典码或者id&#xff0c;实现用户输入的参数校验&#xff0c;最后入库。如果用户输入的参数有问题&#xff0c;返回校验结果给前端。 excel解析使用My-Excel组件&#xff0c;校验使用hibernate-validator&#xff…

高效管理 Nginx 的利器:nginxWebUI 指南和 Docker 部署安装过程

前言 Nginx WebUI 是一个为 Nginx 提供图形化管理界面的工具。通过 WebUI&#xff0c;用户可以轻松管理 Nginx 配置&#xff0c;而无需直接编辑配置文件&#xff0c;尤其适合新手用户和频繁修改配置的场景。 官网文档&#xff1a;nginxWebUI - 文档 本文将分享为什么选择 ngin…

SpringCloud源码-openFeign

LoadBalancer默认只有nacos服务发现器 openFeign与springcloud loadbalancer的结合点 openFeign通过spring cloud loadbalancer进行负载均衡&#xff0c;spring cloud loadbalancer通过discovery client获取nacos的机器列表&#xff0c;然后底层进行负载均衡。

基于微信小程序的校园自助打印系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

从 ELK Stack 到简单 — Elastic Cloud Serverless 上的 Elastic 可观察性

作者&#xff1a;来自 Elastic Bahubali Shetti, Chris DiStasio 宣布 Elastic Cloud Serverless 上的 Elastic Observability 正式发布 — 一款完全托管的可观察性解决方案。 随着组织规模的扩大&#xff0c;一个能够处理分布式云环境的复杂性并提供实时洞察的可观察性解决方…

21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)(非强制登录版本完结)>

PS&#xff1a; 开闭原则 定义和背景 开闭原则&#xff08;Open-Closed Principle, OCP&#xff09;&#xff0c;也称为开放封闭原则&#xff0c;是面向对象设计中的一个基本原则。该原则强调软件中的模块、类或函数应该对扩展开放&#xff0c;对修改封闭。这意味着一个软件实体…

三、GIT与Github推送(上传)和克隆(下载)

GIT与Github推送&#xff08;上传&#xff09;和克隆&#xff08;下载&#xff09; 一、配置好SSH二、在Github创建仓库三、git克隆&#xff08;下载&#xff09;文件四、git推送&#xff08;上传&#xff09;文件到远程仓库 一、配置好SSH Git与Github上传和下载时需要使用到…

【数字化】华为一体四面细化架构蓝图

导读&#xff1a;华为的“一体四面”企业架构设计方法是一种综合性的管理框架&#xff0c;它通过业务架构、信息架构、应用架构和技术架构的集成设计&#xff0c;构建出一个既符合业务需求&#xff0c;又具备高度灵活性和可扩展性的IT系统。这种架构设计方法强调从业务视角出发…

【linux板卡】lubancat通过vnc远程访问桌面

鲁班猫开发板通过远程VNC连接桌面&#xff1a; 硬件&#xff1a;lubancat2&#xff0c;网线 软件&#xff1a;ssh软件&#xff0c;vnc viewer 参考链接&#xff1a;https://training.eeworld.com.cn/video/38821 1、ssh连接lubancat2 &#xff0c;输入ifconfig查看ip 2、输入 …

解决Springboot整合Shiro+Redis退出登录后不清除缓存

解决Springboot整合ShiroRedis退出登录后不清除缓存 问题发现问题解决 问题发现 如果再使用缓存管理Shiro会话时&#xff0c;退出登录后缓存的数据应该清空。 依赖文件如下&#xff1a; <dependency><groupId>org.springframework.boot</groupId><arti…

2024国城杯 Web

这四道题目Jasper大佬都做了镜像可以直接拉取进行复现 https://jaspersec.top/2024/12/16/0x12%20%E5%9B%BD%E5%9F%8E%E6%9D%AF2024%20writeup%20with%20docker/ n0ob_un4er 这道题没有复现成功, 不知道为啥上传了文件, 也在 /tmp目录下生成了sess_PHPSESSID的文件, 但是就是…

el-input输入框需要支持多输入,最后传输给后台的字段值以逗号分割

需求&#xff1a;一个输入框字段需要支持多次输入&#xff0c;最后传输给后台的字段值以逗号分割 解决方案&#xff1a;结合了el-tag组件的动态编辑标签 那块的代码 //子组件 <template><div class"input-multiple-box" idinputMultipleBox><div>…

Ubuntu 22.04.5 修改IP

Ubuntu22.04.5使用的是netplan管理网络&#xff0c;因此需要在文件夹/etc/netplan下的01-network-manager-all.yaml中修改&#xff0c;需要权限&#xff0c;使用sudo vim或者其他编辑器&#xff0c;修改后的内容如下&#xff1a; # Let NetworkManager manage all devices on …

基于SpringBoot的宠物寄养系统的设计与实现(源码+SQL+LW+部署讲解)

文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…

【Linux】:线程安全 + 死锁问题

&#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 线程安全和重入问题&…

Mysql超详细安装配置教程(保姆级)

目录 一、下载Mysql 二、安装Mysql 三、配置Mysql 四、连接Mysql 五、部分疑难问题 一、下载Mysql 从官网下载MySQL&#xff0c;这里我选用的是Mysql8.0.34版本 二、安装Mysql 下载完成后直接双击进行安装&#xff0c;打开后的页面如下所示&#xff1a; “Developer Defa…

Maple软件的安装和使用

文章目录 1.前言说明2.我为什么要学习Maple3.软件的安装4.如何使用4.1基本的赋值语句4.2函数的定义4.3三个类型的书写介质 5.指数运算5.1使用面板5.2自己输入 6.对数的使用 1.前言说明 众所周知&#xff0c;我虽然是一名这个计算机专业的学生&#xff0c;但是我对于数学&#…

Sqoop的使用

每个人的生活都是一个世界&#xff0c;即使最平凡的人也要为他那个世界的存在而战斗。 ——《平凡的世界》 目录 一、sqoop简介 1.1 导入流程 1.2 导出流程 二、使用sqoop 2.1 sqoop的常用参数 2.2 连接参数列表 2.3 操作hive表参数 2.4 其它参数 三、sqoop应用 - 导入…

FFmpeg 4.3 音视频-多路H265监控录放C++开发二十一.4,SDP协议分析

SDP在4566 中有详细描述。 SDP 全称是 Session Description Protocol&#xff0c; 翻译过来就是描述会话的协议。 主要用于两个会话实体之间的媒体协商。 什么叫会话呢&#xff0c;比如一次网络电话、一次电话会议、一次视频聊天&#xff0c;这些都可以称之为一次会话。 那为什…

[极客大挑战 2019]HardSQL 1

看了大佬的wp&#xff0c;没用字典爆破&#xff0c;手动试出来的&#xff0c;屏蔽了常用的关键字&#xff0c;例如&#xff1a;order select union and 最搞的是&#xff0c;空格也有&#xff0c;这个空格后面让我看了好久&#xff0c;该在哪里加括号。 先传入1’ 1试试&#…