当前位置: 首页 > article >正文

【前端,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) + d
    for(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)  // 首先打印 log
        return 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 - b

function processArray(a: number[]) {
    let compCount = 0
    const 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 = 2

const a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

console.log(filterArray(a, (v) => isGoodNumber(GOOD_FATOR, v)))


http://www.kler.cn/a/465388.html

相关文章:

  • 成都和力九垠科技有限公司九垠赢系统Common存在任意文件上传漏洞
  • 以太网ICMP协议(ping指令)——FPGA学习笔记25
  • 离散数学 期末笔记
  • Framebuffer 驱动
  • 《普通逻辑》学习记录——命题的判定与自然推理
  • vite-plugin-imagemin安装问题
  • 自动化办公 | 根据成绩进行自动评级
  • 昆仑万维大数据面试题及参考答案
  • 基于基本滤波器的图像滤波理论与实验分析-附Matlab源程序
  • Lambda 表达式学习
  • springboot3+vue项目实践-黑马
  • 力扣-数据结构-7【算法学习day.78】
  • 周末总结(2024/12/28)
  • 解決當前IP地址僅適用於本地網路
  • 在 Blazor 和 ASP.NET Core 中使用依赖注入和Scoped 服务实现数据共享方法详解
  • Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)
  • 【SpringBoot教程】IDEA快速搭建正确的SpringBoot版本和Java版本的项目
  • PCA降维算法详细推导
  • UE5材质节点Camera Vector/Reflection Vector
  • 2024-12-29-sklearn学习(26)模型选择与评估-交叉验证:评估估算器的表现 今夜偏知春气暖,虫声新透绿窗纱。
  • 【MySQL】通过 Binlog 恢复MySQL数据
  • 解决Docker国内网络问题
  • Yeelight易来与Control4达成战略合作,开启智能家居全球战略新篇
  • Servlet中配置和使用过滤器
  • 《Vue3实战教程》40:Vue3安全
  • k8s启动报错