【前端,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)))
相关文章:
【前端,TypeScript】TypeScript速成(六):函数
函数 函数的定义 定义一个最简单的加法函数: function add(a: number, b: number): number {return a b }(可以看到 JavaScript/TypeScript 的语法与 Golang 也非常的相似) 调用该函数: console.log(add(2, 3)) // out [LOG…...

React引入Echart水球图
在搭建React项目时候,遇到了Echart官方文档中没有的水球图,此时该如何配置并将它显示到项目中呢? 目录 一、拓展网站 二、安装 三、React中引入 1、在components文件夹下新建一个组件 2、在组件中引入 3、使用水波球组件 一、拓展网站 …...

谷歌浏览器的智能推荐功能使用指南
谷歌浏览器作为全球最受欢迎的网络浏览器之一,以其强大的功能和简洁的界面深受用户喜爱。其中,智能推荐功能通过利用先进的算法和数据分析,为用户提供个性化的内容推荐,大大提升了上网体验。本文将详细介绍如何开启和使用谷歌浏览…...

GitHub 上排名前 11 的开源管理后台(Admin Dashboard)项目
如果你是一名开发者,经常处理数据或参与项目管理,那么这篇文章绝对值得收藏!当你需要一个高效、易用的管理后台(Admin Dashboard)项目时,本文会给你灵感。 在现代企业管理和业务运营中,管理后台…...

【运维】部署MKDocs
部署MKDocs obsidian 记录笔记,通过 mkdocs 私有化部署。 1 使用MKDocs创建笔记 创建仓库,安装 Material for MkDocs 和 mkdocs-minify-plugin mkdir tmp cd tmp git initpip install mkdocs-material pip install mkdocs-minify-pluginmkdocs new .2 …...

C# 读取多种CAN报文文件转换成统一格式数据,工具类:CanMsgRead
因为经常有读取CAN报文trace文件的需求,而且因为CAN卡不同、记录软件不同会导致CAN报文trace文件的格式都有差异。为了方便自己后续开发,我写了一个CanMsgRead工具类,只要提供CAN报文路径和CAN报文格式的选项即可将文件迅速读取转换为统一的C…...

计算机网络 (8)物理层的传输方式
一、串行传输与并行传输 串行传输 定义:串行传输是一种数据传输方式,指的是逐位地按照顺序传输数据。在串行传输中,数据位逐个按照一定的顺序进行传输,可以通过单条线路或信道进行。特点: 逐位传输:串行传输…...
【C#】WPF设置Separator为垂直方向
1. 方法1 <Separator BorderBrush"Gray"><Separator.LayoutTransform><RotateTransform Angle"90" /></Separator.LayoutTransform> </Separator>2. 方法2 <Separator Style"{StaticResource {x:Static ToolBar.S…...

太速科技-519-基于ZU19EG的4路100G光纤的PCIe 加速计算卡
基于ZU19EG的4路100G光纤的PCIe 加速计算卡 一、板卡概述 本板卡系我司自主设计研发,基于Xilinx公司Zynq UltraScale MPSOC系列SOC XCZU19EG-FFVC1760架构,支持PCIE Gen3x16模式。其中,ARM端搭载一组64-bit DDR4,总容量达…...

安卓入门二 Kotlin基础
Kotlin Kotlin的历史 Kotlin由Jet Brains公司开发设计,2011年公布第一版,2012年开源。 2016年发布1.0正式版,并且Jet Brains在IDEA加入对Kotlin的支持,安卓自此又有新的选择。 2019年谷歌宣布Kotlin成为安卓第一开发语言&#x…...

C++ ——— 单/多参数构造函数的隐式类型转换和 explicit 关键字
单参数构造函数 代码演示: class A { public:A(int i):_a(i){}private:int _a; }; 在 A 这个类中的构造函数只有一个参数,这就称之为单参数的构造函数 不同形式实例化对象 代码演示: A a1(1);A a2 2; a1 的实例化过程: 第…...
Java编程规约:集合处理
文章目录 I 集合处理【强制】【推荐】II 知识扩展I 集合处理 【强制】 不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请使用 iterator 方式,如果并发操作,需要对 iterator 对象加锁。// 正例: List<String> list = new ArrayList<>(...

IOS safari 播放 mp4 遇到的坎儿
起因 事情的起因是调试 IOS 手机下播放服务器接口返回的 mp4 文件流失败。对于没调试过移动端和 Safari 的我来说着实费了些功夫,网上和AI也没有讲明白。好在最终大概理清楚了,在这里整理出来供有缘人参考。 问题 因为直接用 IOS 手机的浏览器打开页面…...

plsql :用户system通过sysdba连接数据库--报错ora-01031
一、winR cmd通过命令窗口登录sys用户 sql sys/[password]//localhost:1521/[service_name] as sysdba二、输入用户名:sys as sysdba 三、输入密码:自己设的 四、执行grant sysdba to system; 再去PL/SQL连接就可以了...

LabVIEW条件配置对话框
条件配置对话框(Configure Condition Dialog Box) 要求:Base Development System 当右键单击**条件禁用结构(Conditional Disable Structure)**并选择以下选项时,会显示此对话框: Add Subdiagr…...
PyAudio库基本知识详解——为自制PCM音频播放器做准备
前言 结合前段时间我们做的音频编解码器,这样我们就可以将获取到的ADPCM数据,转换成PCM数据,然后播放出来,得到一个完整的音频数据,因此,接下来几篇文章中,我们想做一个播放PCM格式的音频播放器…...
Git如何添加子仓库
背景 项目中经常使用别人维护的模块,在git中使用子模块的功能能够大大提高开发效率。 使用子模块后,不必负责子模块的维护,只需要在必要的时候同步更新子模块即可。 本文主要讲解子模块相关的基础命令,详细使用请参考main page…...

001__VMware软件和ubuntu系统安装(镜像)
[ 基本难度系数 ]:★☆☆☆☆ 一、Vmware软件和Ubuntu系统说明: a、Vmware软件的说明: 官网: 历史版本: 如何下载? b、Ubuntu系统的说明: 4、linux系统的其他版本:红旗(redhat)、dibian、cent…...

在国产电脑上运行PDFSAM软件使用pdf分割合并交替混合处理pdf文档
软件下载地址: https://sourceforge.net/projects/pdfsam/files/ 需要注意事项,系统需要java环境,确认系统有java环境,根据软件版本需求安装对应的java运行环境。 下载pdfsam-4.3.4-linux.tar.gz安装包,解压,将runt…...

STM32完全学习——FATFS0.15移植SD卡
一、下载FATFS源码 大家都知道使用CubMAX可以很快的将,FATFS文件管理系统移植到单片机上,但是别的芯片没有这么好用的工具,就需要自己从官网下载源码进行移植。我们首先解决SD卡的驱动问题,然后再移植FATFS文件管理系统。 二、SD…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...