TypeScript学习笔记(四):函数

时间:2021-04-29 16:02:04

这篇笔记我们来看看TypeScript中的函数。

函数类型

在JavaScript中存在两种定义函数的方法,如下:

1 //命名函数
2 function add(x, y) {
3 return x+y;
4 }
5
6 //匿名函数
7 var myAdd = function(x, y) { return x+y; };

在TypeScript中对应的写法如下:

1 function add(x: number, y: number): number {
2 return x+y;
3 }
4
5 var myAdd = function(x: number, y: number): number { return x+y; };

而TypeScript中对函数的类型也可以定义,比如我们上面的myAdd没有定义类型,则可以将任意类型的函数赋值给它,当然赋值函数以外的东西也可以,这当然是不好的一种做法,我们看看下面的另外一种写法:

var myAdd: (baseValue:number, increment:number)=>number = 
function(x: number, y: number): number { return x+y; };

这里我们将myAdd定义为必须是函数,同时必须是带有两个number参数返回值为number的函数,其它类型的函数赋值给myAdd会报错。

定义函数类型

看到这里你是不是焕然大悟了,这不就是C#的委托么?

如果我们在使用到函数类型的地方都采用上面的写法会比较麻烦,所以可以先定义一个函数类型,在要使用到该类型的地方直接定义为该函数的类型即可,如下:

 1 /**
2 * 这里可以看做 C# 中的委托.
3 */
4 interface IProgressHandler
5 {
6 /**
7 * 进度报告方法.
8 * @param progress 进度.
9 * @returns {} 无.
10 */
11 (progress:number):void;
12 }
13
14 class Loading
15 {
16 private _progressHandler:IProgressHandler;
17
18 Load(url:string, callback:IProgressHandler)
19 {
20 this._progressHandler = callback;
21 //加载完毕
22 this._progressHandler(1.0);
23 }
24 }
25
26 function run()
27 {
28 var load: Loading = new Loading();
29 load.Load("http://xxx/", function(p:number):void
30 {
31 alert("加载:" + p);
32 });
33 }
34
35 run();

可选和默认参数

可选参数,表示该参数可以填写也可以不填写,使用?:表示,如下:

 1 function buildName(firstName:string, lastName?:string)
2 {
3 if(lastName)
4 return firstName + " " + lastName;
5 else
6 return firstName;
7 }
8
9 alert(buildName("LiLie"));
10 alert(buildName("Meimei", "Han"));

没有提供实参则lastName为undefined。

默认参数表示不填该参数则使用提供的默认值,如下:

1 function buildName(firstName:string, lastName:string = "Wang")
2 {
3 return firstName + " " + lastName;
4 }
5
6 alert(buildName("LiLie"));//LiLie Wang
7 alert(buildName("Meimei", "Han"));//Meimei Han

对象参数类型

我们看一下下面的写法:

function getArea(quad:Object)
{
return quad["width"] * quad["height"];
}

alert(getArea({width:
10, height:20}));

这种写法存在一个问题,如果传入的实参没有width或height时运行时会报错但编译时不会报错,那么如何才能在编译时就进行类型判断呢?

一般其它语言都是使用接口来解决这个问题,但是TypeScript有一种更快捷的方法实现,如下:

1 function getArea(quad:{width:number, height:number})
2 {
3 return quad.width * quad.height;
4 }
5
6 alert(getArea({width:10, height:20}));

同时也支持可选参数,但不支持默认参数,如下:

 1 function getArea(quad:{width:number, height?:number})
2 {
3 if (quad.height == undefined)
4 {
5 quad.height = 10;
6 }
7 return quad.width * quad.height;
8 }
9
10 alert(getArea({width:10}));

可变参数

可变参数表示可以任意填写任意参数,如下:

1 function buildName(firstName:string, ...restOfName:string[])
2 {
3 alert(restOfName.length);
4 return firstName + "," + restOfName.join(",");
5 }
6
7 alert(buildName("LiLie"));
8 alert(buildName("LiLie", "MeimeiHan"));
9 alert(buildName("LiLie", "MeimeiHan", "LinTao", "LaoWang"));

Lambda

简写的匿名函数,我们已上门的例子来看:

 1 /**
2 * 这里可以看做 C# 中的委托.
3 */
4 interface IProgressHandler
5 {
6 /**
7 * 进度报告方法.
8 * @param progress 进度.
9 * @returns {} 无.
10 */
11 (progress:number):string;
12 }
13
14 class Loading
15 {
16 private _progressHandler:IProgressHandler;
17
18 Load(url:string, callback:IProgressHandler)
19 {
20 this._progressHandler = callback;
21 //加载完毕
22 alert(this._progressHandler(1.0));
23 }
24 }
25
26 function run()
27 {
28 var load: Loading = new Loading();
29 load.Load("http://xxx/", p => {
30 alert("加载:" + p);
31 return "Hello Lambda!";
32 });
33 }
34
35 run();

TypeScript的Lambda使用和C#中一致。

Lambda和this

我们看一下这个例子:

1 var messenger = {
2 message: "Hello World",
3 start: function() {
4 setTimeout(() => { alert(this.message); }, 3000);
5 }
6 };
7 messenger.start();

编译后的js如下:

 1 var messenger = {
2 message: "Hello World",
3 start: function () {
4 var _this = this;
5 setTimeout(function () {
6 alert(_this.message);
7 }, 3000);
8 }
9 };
10 messenger.start();

更多消息可以查看:http://www.codebelt.com/typescript/arrow-function-typescript-tutorial/

重载

TypeScript的函数支持重载,同名函数可以根据参数类型及数量的不同来执行不同的逻辑,不过定义重载函数和其它语言稍微不同:在TypeScript中需要先写一些同名的函数声明,然后在一个同名函数里写出实现,而且需要自己判断参数类型(比较鸡肋):

 1 function attr(name: string): string;
2 function attr(name: string, value: string): Accessor;
3 function attr(map: any): Accessor;
4
5 function attr(nameOrMap: any, value?: string): any {
6 if (nameOrMap && typeof nameOrMap === "object") {
7 // handle map case
8 }
9 else {
10 // handle string case
11 }
12 }