在JavaScript中,函数是一等公民。在TypeScript中虽然已经支持类,命名空间和模块,但函数的使用频率仍然是非常高的,而且还添加了额外的功能,使用起来更方便了。
函数定义
先来看一下在TypeScript中函数的定义。
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number) {
return x + y
};
console.log(myAdd(2, 3));
TypeScript能够根据返回语句自动推断出返回值类型,因此我们通常省略它。
下面让我们写出函数的完整类型。
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number {
return x + y;
}
console.log(myAdd(2, 3));
- 函数类型包含两部分:参数类型和返回值类型。 当写出完整函数类型的时候,这两部分都是需要的。
- 我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型,这个名字只是为了可读性,可以与函数参数中的名字不同。
- 第二部分是返回值类型。 对于返回值,我们在函数和返回值类型之前使用( =>)符号,使之清晰明了。 如之前提到的,返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为 void 而不能留空。
在一边指定了类型但是另一边没有类型的话,编译器会自动推断类型。如:
let myAdd: (x: number, y: number) => number =
function(x, y) {
return x + y;
}
console.log(myAdd(2, 3));
可选参数和默认参数
函数支持可选参数和默认参数。
let myAdd: (x: number, y?: number) => number =
function(x, y) {
if (y) {
return x + y;
} else {
return x + 3;
}
}
function add(x: number, y = 3): number {
return x + y;
}
console.log(myAdd(2));
console.log(add(2));
- 参数名称后面跟着?表示是可选参数,调用的时候可以不传这个参数。
- 参数名称后面直接跟 = 值 表示这个参数有默认值,当调用函数时不传递这个参数或传了个 undefined ,函数会使用这个默认值。
- 如果带默认值的参数后面还有不带默认值的非可选参数,那么调用函数的时候这个带默认值的参数位置必须传值或是使用 undefined ,意思是不能跳过这个带默认值的参数(如:function add( y = 3, x: number),则调用函数使用add(3, 2)或 add(undefined, 2))。
剩余参数
当我们不知道一个函数里会传递多少个参数时,就会用到 剩余参数。
function build(name: string, ...names: string[]) {
return name + names.join("");
}
let buildFun: (x: string, ...y: string[]) => string = build;
console.log(buildFun('hello', ', ', 'world', '!'));
//hello, world!
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。
this
当返回一个函数或将函数当做参数传递的时候,确定 this值会变的很难。
let demo = {
name: 'Demo',
show: function() {
console.log(this);
return function() {
console.log(this);
console.log(this.name);
}
}
}
let d = demo.show();
d();//undefined
我们在对象的show方法里返回了一个函数。这个返回函数里面this已经变掉了,不再是当前对象。
对象的show方法中的 this 打印出来是当前对象Object {name: "Demo"} 。它里面定义的返回函数里打印的 this 是一个 global(全局)对象,如果开启严格模式的话,会是 undefined 。
通过使用ES6中的箭头函数可以解决这个问题,箭头函数能保存函数创建时的 this值,而不是调用时的值。
let demo = {
name: 'Demo',
show: function() {
console.log(this);
return ()=> {
console.log(this.name);
}
}
}
let d = demo.show();
d();//Demo
箭头函数会保存 创建这个箭头函数的当前对象 的this值。这时候鼠标放到箭头函数里面的this上会发现这个this是一个 any 类型,同时 this.name 也是一个 any 类型。这是因为 this来自对象里的函数表达式。
可以用如下的解决办法提供一个显式的 this参数,处理this变成any类型。this参数是个假的参数,它出现在参数列表的最前面
interface Ani {
name: string;
show(this: Ani): ()=> void;
}
let ani: Ani = {
name: 'Ani',
show: function(this: Ani) {
return ()=> {
console.log(this.name);
}
}
}
let a = ani.show();
a();//Ani
现在鼠标放到箭头函数的this上发现它的类型正确了,是Ani。
重载
让函数根据传入的不同参数类型,返回不同的值类型,需要用到重载。通过为同一个函数提供多个函数类型定义来进行函数重载。 编译器会根据这个函数定义列表去处理函数的调用。
function Add(a: number, b: number): number;
function Add(x: string, y: string): string;
function Add(x, y): any {
if (typeof x == 'number') {
console.log(x + y);
} else if (typeof x == 'string') {
console.log(x + ' ' + y);
}
}
Add(3, 5);//8
Add('Hello', 'world!');//Hello world!
我们给函数定义了两种类型,一个接收 number 类型参数,返回也是 number 类型;另一个接收 string类型参数,返回是 string 类型。
通过重载,我们的函数既可以处理 number 类型参数的调用,又可以处理 string 类型参数的调用。
网友评论