【前端,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…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
