让前端飞

TS中的函数

2020-10-15  本文已影响0人  前端辉羽

本文目录:

函数的几个基本概念:

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.可选参数和默认参数

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.剩余参数

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.函数重载

现在有这样一个需求: 我们有一个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并不是重载列表的一部分,因此这里只有两个重载:一个是接收数字,另一个接收字符串。 以其它参数调用会产生错误

上一篇 下一篇

猜你喜欢

热点阅读