函数类型-3:函数重载

简介: 本实验将介绍TypeScript中的函数重载

函数类型-3:函数重载


1. 创建资源

开始实验之前,您需要先创建实验相关资源。

  1. 在实验室页面,单击创建资源
  2. (可选)在实验室页面左侧导航栏中,单击云产品资源列表,可查看本次实验资源相关信息(例如IP地址、子用户信息等)。

说明:资源创建过程需要3~5分钟视资源不同开通时间有所差异,ACK等资源开通时间较长。完成实验资源的创建后,您可以在云产品资源列表查看已创建的资源信息,例如:子用户名称、子用户密码、AK ID、AK Secret、资源中的项目名称等。

实验环境一旦开始创建则进入计时阶段,建议学员先基本了解实验具体的步骤、目的,真正开始做实验时再进行创建。

资源创建成功,可在左侧的资源卡片中查看相关资源信息以及RAM子账号信息

2. 实验环境操作指南

在本系列实验中,有两种方法可以进行操作。一种是控制台方式,另一种是远程桌面的方式。接下来我们分别介绍这两种操作方式。

控制台方式

使用控制台方式操作实验,上手比较简单,对网络带宽的要求也不高。但是在编辑代码时,需要使用Vim工具进行文本编辑。对于初学者来说使用Vim工具需要熟悉其操作模式。

进入控制台环境

资源创建成功后,我们在右侧选择切换到Web Terminal

切换到dev用户

本次实验的开发环境部署在dev用户的~/web目录中。因此我们执行这两条命令即可进入实验环境

su dev
cd ~/web

Vim工具的用法

vim是一个命令行下的文本编译器。使用vim编辑文件时。我们只需要通过快捷键,而不需要鼠标就可以对文本文件进行编辑。但是这种文本编辑器的用法和常见的图形界面编辑器使用习惯差别较大。接下来我们简单介绍vim的使用。

3.1 进入Vim

在命令行中输入vim即可进入操作界面,这时的Vim没有打开任何文件。

vim

3.2 Vim的三种模式

和普通编译器不同的是,Vim包含了三种操作模式。分别是命令模式编辑模式末行模式。接下来我们来简单介绍一下三种模式的用法。

3.3 命令模式

在刚进入界面的时候,vim默认状态为命令模式。这种模式下,无法编辑文件,键盘输入也不会在屏幕上有任何显示,这种情况往往会让使用者感到困惑。这时候我们可以输入大写的ZZ,即可退出Vim。

3.4 编辑模式

我们继续输入vim回到编辑器。在命令模式下我们按下小写的i。此时我们会发现下部的提示已经变成了插入。这表示vim已经进入了编辑模式。

在编辑模式下我们就可以像正常的编辑器一样编辑文件。此处我们输入hello world

        在编辑完成之后,如果我们想退回命令模式,只需要按ECS键即可。按下该按钮之后我们会发现下部的插入提示消失了,这就表示vim回到了命令模式。

3.5 末行模式

回到命令模式之后,我们按下:键,这时下部的提示会变成:,这就表示vim进入了末行模式。在末行模式下,我们同样使用快捷命令操作vim,但是和命令模式不同的是,末行模式中输入的命令会显示的屏幕的最后一行。

接下来我们继续输入w demo.txt并按回车。会提示显示为如下内容。表示上面的内容已经保存到了demo.txt中。

最后我们按:q,该命令也可以退出vim。

4. 编辑index.js文件

4.1 创建新文件

当我们希望编辑特定文件时,我们可以输入vim 文件名。这时候在下部会看到"index.ts" [新]。表示vim自动创建了新文件。

vim index.ts

4.2 复制粘贴

在编辑模式下,vim同样可以使用ctrl+v进行粘贴。我们按i进入编辑模式之后,将下列内容粘贴到vim中。

//vim编辑模式和命令模式的常用命令:
//在编辑模式中:可以使用 上 下 左 右 按键移动光标
//在命令模式中:可以使用 h j k l 命令移动光标
//在编辑模式中:可以使用退格或者DEL键删除字符
//在命令模式中:可以使用 x 命令删除字符
//在命令模式中:可以使用 dd 命令删除整行文字(谨慎使用!)
//在命令模式中:可以使用 ggdG 命令删除全部文字(谨慎使用!)
//在命令模式中:可以使用 u 命令撤销操作
//在命令模式中:可以使用 ctrl + r 命令重做操作。

4.3 文件内容的查找

在命令模式下,除了按:命令之外,还可以使用/命令进入末行模式,通过/进入末行模式之后,输入相关的内容即可进行全文检索。我们在命令模式下输入/dd

光标就会移动到相关字符上。

4.3 文件的保存和放弃

当我们编辑完成之后,可以在命令模式中通过ZZ命令直接保存并退出编辑器,也可以通过在末行模式中通过:w单独保存文件。如果我们希望通过末行模式保存并退出,可以使用:wq

但是需要注意的时,如果文件在修改之后没有保存,是无法通过:q退出的。如果编辑过的文件是只读属性也无法通过ZZ退出。这时我们就可以使用:q!命令放弃所有的编辑内容,强制退出vim。

远程桌面方式

使用远程桌面方式进行实验是,可以使用VS Code编译器进行代码的编写和操作,相对控制台方式更加的直观。但是这种方式对网络带宽的要求比较高。

进入网页环境

1.1 进入远程桌面

资源创建成功后,我们在右侧选择切换到远程桌面

1.2 启动浏览器

在远程桌面页面中,点击Chromium网页浏览器

登录RAM用户

2.1 打开网页

浏览器启动后会默认打开阿里云的RAM用户登录页。在登录页面中我们点击下一步按钮。

2.2 获取密码

接下来我们需要输入RAM用户的密码。密码显示在实验控制台左侧,我们点击子用户密码右侧的复制按钮。

复制完成后,我们在用户密码框中按Ctrl + V 复制密码,然后点击登录按钮

进入ECS的远程连接。

3.1 进入ECS控制台

登录成功后,页面跳转到控制台,我们在控制台的搜索框中输入ECS,然后点击云服务器ECS进入云服务器控制台。

3.2 进入远程连接界面

在ECS控制台中,我们找到实验创建的ECS,点击右侧的远程连接按钮。

3.3 选择VNC远程连接

在远程连接中选择通过VNC远程连接中的立即登录如果没有显示该选项,则可点击展开其他登录方式按钮。

登录VNC远程连接

4.1 初始化VNC密码

初次登录VNC远程连接时需要先设置VNC密码。点击重置VNC密码按钮。

输入两次新的VNC密码,并点击确认

4.2 登录VNC

VNC密码设置成功后,输入密码并点击确认。

4.4 进入图形界面

VNC登录成功后会看到实验ECS的登录界面,在登陆界面中我们点击DEV用户图标

4.5 在图形界面中登录

在密码框中输入默认登录密码Dev12345。即可进入图形实验环境

使用VS Code编辑器

登录图形实验环境之后,接下来我们来启动VS Code 编辑器。

5.1 进入应用程序列表

首先我们点击界面的下方的显示应用程序按钮。

5.2 启动VS Code

在应用程序列表中选择最后一页

然后点击VS Code应用图标

5.3 选择文件

在VS Code 编译器中,左边区域为文件列表,可以选择要编辑的文件

5.4 编辑文件

在VS Code中,右上区域为文件编辑区,可以进行文件内容编辑

5.5 操作终端

在右下区域的终端选项卡,为控制台区域,可以进行命令输入执行

3. 函数重载的定义

在TypeScript的函数中,还有一种情况非常常见的情况,也就是同一个函数名可以支持不同的参数类型,不同的参数个数。利用最常见的console.log函数。这种情况下,除了使用联合类型,可选参数之外,TypeScript还提供了另一种方法,也就是函数重载。在本实验中我们就来学习函数重载的的用法和注意事项。

  1. 传统的函数重载的局限。

在之前的实验中,我们可以使用联合类型,来支持函数的多种参数类型和多种返回类类型。但是这种方法本身也具有一些缺陷。在下面的例子中我们创建一个最简单的函数fun,该函数可以接受number或者string类型的参数。这个函数不对参数做任何操作,直接将参数返回。

这种情况下,我们可以将参数和返回值都设置为number | string类型。但是这样的用法,对于返回值的操作会很麻烦。例如我们传入了一个number类型的参数1。自然希望返回值也作为number类型。但是由于返回值为number | string类型,赋值操作就会发生编译错误。我们修改index.ts文件为如下内容。

function fun(val: number | string): number | string {
    console.log("val:", val);
    return val;
}
var r: number = fun(1)

终端选项卡中输入如下内容,编译并查看。

tsc

  1. 函数的单独定义

为了解决联合类型,可选参数等对于函数不同参数和返回值类型的处理局限性,我们先来了解一些函数重载的前置知识。

首先我们来看一下函数的单独定义语法,在下面的例子中,我们在编写函数的时候可以先对函数进行定义,函数定义的语法和普通函数的写法一致,只是不包括函数的实现部分。当函数定义完毕后,我们可以继续对该函数进行实现。需要注意的是函数的定义和实现要一致。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: number): number {
    console.log("number log:" + log);
    return log;
}
logFunction(0);

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. 函数的多重定义

接下来我们来尝试为函数添加另一个参数类型的定义。添加完成之后进行编译,会发现编译提示错误。我们观察编译错误的提示,并不是提示函数多次定义,而是提示函数在定义之后没有实现。

实际上在TypeScript中,对于同一个函数并不限制多次定义,但是在函数定义之后已经要进行实现。我们修改index.ts文件为如下内容。

function logFunction(log: number): void;
function logFunction(log: string): void;

我们在终端选项卡中输入如下内容,编译并查看。

tsc

4. 函数重载的实现

在上一个小节中,我们介绍了函数的单独定义和多重定义。接下来我们来看一下多重定义的函数如何实现。

  1. 函数重载的实现

在TypeScript的同名函数中,无论函数有多少个定义,函数的实现只能有一个。而且这个函数实现必须能够兼容所有的函数定义。也就是只要符合函数定义的参数类型组合,也必须符合函数实现的参数类型。

以下面的例子为例,logFunction函数的两个定义分别可以接受number和string,那么该函数的实现就必须可以接受着两种参数。所以在编写函数实现时,通常也会用联合类型。

当函数实现编写完成之后,我们就可以根据函数定义的参数类型进行函数调用。我们修改index.ts文件为如下内容。

function logFunction(log: number): void;
function logFunction(log: string): void;
function logFunction(log: number | string): void {
    console.log("number log:" + log);
}
logFunction("Hello World")
logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. 不同返回值的实现

接下来我们修改函数的定义和逻辑。将函数的逻辑改为直接返回log参数。同时修改函数的定义,将返回值改为和参数的类型一致。在返回值修改完成后,我们同样需要修改函数实现的返回值。函数返回值的类型同样也需要兼容所有函数声明中的返回值类型。

修改完成之后,我们重新调用函数,并保存返回值。这时候我们发现函数的返回值类型和函数的参数类型可以保持一致了,这是因为TypeScript可以推导我们在调用函数的时候具体使用了哪一个函数的定义。

通过上面的步骤,我们先将函数的定义和实现分离,然后编写不同的函数定义,最后再通过一个函数实现来实现逻辑功能,这个步骤就叫做TypeScript中的函数重载。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string): string;
function logFunction(log: number | string): number | string {
    console.log("log:" + log);
    return log
}
var s: string = logFunction("Hello World")
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. 不同参数个数的实现

当我们了解了函数重载的定义和实现方法之后,再来看一些负载的情况。我们继续修改例子,为其中的一个函数定义添加第二个参数。这种情况下我们编写函数实现的时候,就需要兼容一个参数和两个参数的两种函数定义。

这时候我们常用的方式是为函数实现添加一个可选参数。当我们添加了可选参数之后,采用一个参数的函数调用时,可选参数的值为undefined

需要注意的时,我们在编写函数重载的实现时,可以采用多种方式。例如:为参数添加默认值,使用不定长参数等方式。TypeScript只要求函数实现可以兼容所有的函数定义即可。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, pos: number): string;
function logFunction(log: number | string, pos?: number): number | string {
    console.log("log:" + log + ", pos:" + pos);
    return log
}
var s: string = logFunction("Hello World", 0)
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

5. 函数重载的类型处理

在上面的两个小节中,我们学习了函数重载的定义和实现的基本语法。通过学习我们了解到,函数重载要求在一个函数中实现所有的函数定义,这就要求函数重载会遇到一个参数具有不同的类型,甚至不同的逻辑的情况。

在本小节中我们继续修改上面的例子,我们希望将函数逻辑修改为:当用户传入的参数是number类型的时候,我们直接返回这个参数。当用户传入的参数是string类型时,我们希望获得字符串中的指定位置的字符。接下来本实验会通过这个例子来演示函数重载的类型处理。

  1. 函数重载的逻辑分支

首先我们需要在函数运行时判断log参数的类型,这时我们可以使用typeof关键字,该关键字可以在函数运行时获得并判断一个变量的基本的类型,此处的基本类型指的时stringbooleannumber,更加详细的运行时类型判断,会在后面的实验中进行讲解。

typeof关键字的用法为typeof(变量),该表达式会返回一个字符串,通过该字符串就可以判断变量的类型。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, pos: number): string;
function logFunction(log: number | string, pos?: number): number | string {
    if (typeof log === 'number') {
        console.log("number log:" + log);
        return log
    }
    else {
        console.log("string log:" + log);
        return log
    }
}
var s: string = logFunction("Hello World", 5)
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. 自动类型转换

当我们判断了参数的类型之后,接下来就可以根据不同的参数类型来进行逻辑编写。在编写正式逻辑之前,我们首先尝试当传入参数为string类型的时候,获得字符串的长度。

这时我们会发现虽然log参数的类型是string | number,但是经过typeof判断该参数类型不是number之后,我们就可以直接使用log.length来获得字符串的长度。这是由于TypeScript的编译器会在编译的时候,检查运行时类型判断的语法。然后根据上下文逻辑,智能推导出变量的类型。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, pos: number): string;
function logFunction(log: number | string, pos?: number): number | string {
    if (typeof log === 'number') {
        console.log("number log:" + log);
        return log
    }
    else {
        console.log("string log:" + log);
        console.log("string log length:" + log.length);
        return log
    }
}
var s: string = logFunction("Hello World", 5)
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. !关键字的使用

接下来我们需要判断pos参数的类型。在函数实现中pos是可选参数类型,根据之前的实验我们可知,可选参数的类型为可以等价于普通类型和undefined的联合类型。

在本例中,如果我们希望判断pos是number还是undefined,也可以使用typeof进行运行时判断。但是通过函数的定义我们了解到,只要是函数的第一个参数是string,那么第二个参数一定是number。这个时候我们就可以通过!关键字直接将pos转换为number类型。

在此处使用!关键字进行类型转换的操作又叫做类型断言。在TypeScript中,类型断言是在编译的时候确定函数的类型,而typeof方法叫做类型的运行时类型判断或者动态类型判断,是在程序运行的时候判断对象的类型。

关于类型断言和动态判断的具体用法在后面的实验中还会具体的讲解。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, pos: number): string;
function logFunction(log: number | string, pos?: number): number | string {
    if (typeof log === 'number') {
        console.log("number log:" + log);
        return log
    }
    else {
        log = log.charAt(pos!)
        console.log("string log:" + log);
        return log
    }
}
var s: string = logFunction("Hello World", 5)
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

6. 函数重载的注意事项

在最后一个小节我们再来看一下函数重载在使用过程中的一些注意事项

  1. 函数重载的调用

首先我们来看函数重载的调用,我们观察函数重载的实现,会发现如果按照函数重载实现的参数类型。我们可以将第一个参数设置为number,第二个参数也设置为number。

我们尝试以这种方式调用函数,会发现在编译时会报错。这是因为在函数重载中,无论函数重载的实现如何定义参数类型,我们只能够按照函数重载的定义的参数类型进行调用。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, start: number): string;
function logFunction(log: number | string, start?: number): number | string {
    console.log("log:" + log + ", start" + start);
    return log
}
var s: string = logFunction("Hello World", 0)
var n: number = logFunction(100, 0)

终端选项卡中输入如下内容,编译并查看。

tsc

  1. 返回值的类型

了解函数重载编写中参数的运行时类型判断和类型断言之后,我们再来看一看函数重载中返回值类型的处理逻辑。

我们修改函数重载的实现,故意将将函数的返回值的类型修改为和函数重载的定义不一致。然后我们运行程序,会发现无论是编译器还是在程序运行的时候,都没有发现这个类型错误。这主要是受限于TypeScript的编译器。

因此需要注意的是,在函数重载的实现过程中,我们需要手动保证函数重载的返回值类型的正确。我们修改index.ts文件为如下内容。

function logFunction(log: number): number;
function logFunction(log: string, pos: number): string;
function logFunction(log: number | string, pos?: number): number | string {
    if (typeof log === 'number') {
        console.log("number log:" + log);
        return log + ""
    }
    else {
        log = log.charAt(pos!)
        console.log("string log:" + log);
        return pos!
    }
}
var s: string = logFunction("Hello World", 5)
var n: number = logFunction(100)
console.log(s)
console.log(n)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

  1. 不定长参数的处理

最后我们再来看一个比较复杂的参数例子,我们在第一个函数重载的定义中添加一个不定长参数。在这种情况下,根据我们在之前实验中学到的知识,函数中的可省略参数之后不能再有其他参数。因此函数重载的实现就不能使用可选参数的方式了。

如果遇到这种情况,我们可以使用联合类型的不定长参数的办法来处理。联合类型的不定长参数可以兼容绝大多数函数重载实现时的参数类型。但是这种方式下。我们需要频繁的使用参数的类型断言,同时函数实现的逻辑也变得不利于阅读,因此我们要谨慎的使用这种方式。我们修改index.ts文件为如下内容。

function logFunction(log: number, ...p: string[]): number;
function logFunction(log: string, pos?: number): string;
function logFunction(log: number | string, ...p: (number | string | undefined)[]): number | string {
    if (typeof log === 'number') {
        console.log("number log:");
        return log
    }
    else {
        console.log("string log:" + log);
        return log
    }
}
var s: string = logFunction("Hello World")
var n: number = logFunction(100)

终端选项卡中输入如下内容,编译并查看。

tsc
node index.js

实验地址:https://developer.aliyun.com/adc/scenario/53c465f86eec4730939e27b02312bacf

相关实践学习
通义万相文本绘图与人像美化
本解决方案展示了如何利用自研的通义万相AIGC技术在Web服务中实现先进的图像生成。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情: https://www.aliyun.com/product/ecs
相关文章
|
安全 Java 5G
从源码角度剖析 Elasticserach 段合并调优策略
从源码角度剖析 Elasticserach 段合并调优策略
|
人工智能 自然语言处理 API
Dify 接入通义万象指南
Dify Pipeline集成通义万象, 实现自动化图像生成流程,包含基础流程和完整代码实现。
4742 63
|
敏捷开发 人工智能 自然语言处理
“教育+AI”,阿里云可以做什么?
“教育+AI”,阿里云可以做什么?
|
移动开发 小程序 物联网
智能车位引导系统:智能导航,便捷停车
摘要(Markdown格式): 智慧停车场结合室内定位导航技术,提升停车效率及用户体验。设计包括移动端H5导航小程序、大屏端智能联动,以及基于GIS的物联网管理。系统提供空余车位引导、车位预约、多样化寻车及AR导航等功能,支持与不同停车场系统对接,确保可扩展性。通过优化的离场引导,减少车主寻找出口的时间,整体提升了大型公共场所的客流管理和信息化水平。
1313 3
智能车位引导系统:智能导航,便捷停车
|
编解码 人工智能 文字识别
5款知名度不高,但很好用的软件
本文推荐了5款小众但实用的软件工具:MouseInc可通过手势操作提升效率;TagSpaces以标签化管理文件,打破传统目录结构;燃精灵可检测微信空号,助力精准营销;GIMP作为开源图像编辑器,功能媲美Photoshop;File Converter支持200+格式互转,满足多种文件处理需求。这些工具虽知名度不高,却各具特色,值得尝试。
431 10
|
消息中间件 监控 网络协议
什么是中间件?
一、为什么要中间件 计 算机技术迅速发展。从硬件技术看,CPU速度越来越高,处理能力越来越强;从软件技术看,应用程序的规模不断扩大,特别是Internet及WWW的出 现,使计算机的应用范围更为广阔,许多应用程序需在网络环境的异构平台上运行。
2131 90
|
数据采集 存储 监控
实现自动化数据抓取:使用Node.js操控鼠标点击与位置坐标
本文介绍了如何使用Node.js和Puppeteer实现自动化数据抓取,特别是针对新闻网站“澎湃新闻”。通过设置代理IP、User-Agent和Cookie,提高爬虫的效率和隐蔽性,避免被网站封锁。代码示例展示了如何模拟鼠标点击、键盘输入等操作,抓取并整理新闻数据,适用于需要规避IP限制和突破频率限制的场景。
883 10
|
设计模式 前端开发 数据库
理解mvc架构
mvc架构
390 5
|
项目管理
推荐5款好用靠谱的工时管理工具
在快节奏的工作环境中,精准的工时记录与高效的项目管理至关重要。本文推荐五款工时管理软件:Trello界面简洁但功能较简单;Worktile功能丰富但操作复杂;Clockify专注工时追踪与报告生成;Asana功能全面但价格昂贵;板栗看板简洁高效,易于上手,特别适合预算有限的团队。选择合适的工具,提升团队效率。