本文目录:
- 1.函数定义的两种方式
- 2.函数类型
- 3.可选参数和默认参数
- 4.剩余参数
- 5.函数重载
函数的几个基本概念:
- 一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要给函数的参数和返回值都设置一个类型
- 函数有个特点:函数内部可以使用函数体外部的变量
-
TypeScript
的函数类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。 在 ES6 中,=> 叫做箭头函数 - 后面我们会用接口来定义函数的形状,避免我们在函数的定义那里写的代码过于臃肿,让代码结构更清晰
1.函数定义的两种方式
// 函数声明
function add(x, y) {
return x + y;
}
// 函数表达式
let add1 = function add1(x, y) {
return x + y;
};
上面的代码如果我们进行如下的调用
console.log(add(1.'2')) //12
console.log(add(2,true)) //3
JS中存在隐式转换,当字符串和数字相加的时候,数字会被转换为字符串,当数字和boolean进行相加的时候,boolean会被转换为数字(false转为0,true转为1),所以上面代码的输出结果并不是我们想要的,而这种bug如果出现在实际项目中,往往是难以定位的。
我们之前说过,任何的js代码都可以不改代码的情况下,直接将后缀名改为ts,可以正常的运行; 是因为ts的类型推断,会自动的根据我们传入的变量和返回的值进行判断
// 我们使用ts的形式来定义两个函数
function add(x: number, y: number): number {
return x + y;
}
let add2 = function(x: number, y: number): number {
return x + y;
};
但是我们这里的add2是一个变量,我们没有给它指定类型,它是由等号右边的值 由编译器自动推断出来add2是一个函数的,我们要自定义一个函数类型; 涉及到参数和返回值
2.函数类型
在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。 在 ES6 中,=> 叫做箭头函数,但是在TS中,=>表示函数定义
let add2: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y;
};
上面就是函数类型, 类似于之前学过的联合类型,枚举类型,类型别名等自定义类型。当然了=>左边的参数名称x,y都是可以随意更改的,在实际工作中,我们不会使用上面的方式去定义函数类型,因为这样写的代码太臃肿了,我们会用接口的形式,这部分知识后面会讲。
Interface Myfn {
(xll: number,yll: number): number
}
let add3:MyFn = add //add就是本文上面的代码已经定义好的函数
3.可选参数和默认参数
-
JavaScript
里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined - 在
TypeScript
里参数多了或者少了都是不被允许的;但是我们可以在参数名旁使用 ?实现可选参数的功能 - 可选参数必须接在必需参数后面,也就是可选参数后面不允许再出现必需参数了
- 在 ES6 中,我们允许给函数的参数添加默认值,
TypeScript
会将添加了默认值的参数识别为可选参数
function fullName(firstName: string, lastName?: string) {
console.log(lastName);
return firstName + ' ' + lastName;
}
如果不加?, 这个函数我们就只能传递2个参数,多了少了编译都会失败;但是在js里面如果不传,返回值就是undefined
如果加上了?, 那这个函数第一个参数还是必传,第二个参数可传可不传
console.log(fullName('123', '456'));
console.log(fullName('123'));
可选参数必须接在必选参数后面; 下面这样定义函数就会编译报错
function buildName2(firstName?: string, lastName: string) {
return firstName + ' ' + lastName;
}
接下来我们来看一下默认参数
function buildName2(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat1 = buildName2('Tom', 'Cat');
let tom1 = buildName2('Tom');
第二次函数调用只传入了一个参数,因为我们ts会将添加了默认值的参数设置为可选参数, 即使不传递也可以,就是用的默认值Cat
4.剩余参数
- 必要参数,默认参数和可选参数有个共同点:它们表示某一个参数
- 想同时操作多个参数,或者你并不知道会有多少参数传递进来, 在
js
里面使用arguments来访问所有传入的参数 - 在TypeScript`里,你可以把所有参数收集到一个变量里; 使用...扩展运算符
function getBalls(x: string, ...restOfName: string[]) {
console.log(restOfName);
return x + ' ' + restOfName.join(' ');
}
let myBalls = getBalls('basketball', 'football', 'tennis', 'baseball');
console.log(myBalls);
上面的代码中 restOfName实际上是一个数组。所以我们可以用数组的类型来定义它
restOfName剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字
并且要注意 rest 参数只能是最后一个参数
5.函数重载
- 同名函数的参数的个数、类型或者顺序必须不同(其中有一个不一样就满足条件了) 叫函数的重载
- 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。 为同一个函数提供多个函数类型定义来进行函数重载
- 在定义重载的时候,一定要把最精确的定义放在最前面。因为查找重载列表,会从第一个重载定义开始使用,如果匹配成功的话就使用,否则就继续向下查下;最后函数实现时,需要使用 |操作符或者?操作符,把所有可能的输入类型全部包含进去(不确实的话可以写any)
- 函数重载的意义在于能够让你知道传入不同的类型参数得到不同的类型结果,如果传入的参数不同,但是得到的结果(类型)却相同,那么这里就不需要使用函数重载
现在有这样一个需求: 我们有一个add函数,它可以接收string类型的参数进行拼接,也可以接收number类型的参数进行相加
下面是按照之前我们所学知识写的代码
function add(arg1: string | number, arg2: string | number): number | string{
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2;
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2;
}
}
let a1 = add(1, 2);
let a2 = add('a', 'b');
上面的代码在调用函数的时候,定义的变量a1和a2没有去定义类型,只是用了根据等号右边的值去赋值给左边的变量,事实上,a1和a2也不能去指定为string或者number,因为add函数的返回值就是一个联合类型number | string,所以是实际工作中如果发生了这种事情,会导致a1和a2使用变得非常混乱,接下来我们使用函数重载的形式对代码进行优化
先进行函数的重载,定义函数,将参数和返回值的类型定死
function add(arg1: string, arg2: string): string;
function add(arg1: number, arg2: number): number;
接下来进行函数的实现
function add(arg1: string | number, arg2: string | number): number | string{
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2;
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2;
}
}
let a1 = add(1, 2);
let a2 = add('a', 'b');
这时候就可以明确a1和a2的类型了,a1是number类型,a2是string类型
注意,function add(arg1: string | number, arg2: string | number): number | string并不是重载列表的一部分,因此这里只有两个重载:一个是接收数字,另一个接收字符串。 以其它参数调用会产生错误
网友评论