這篇筆記我們來看看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 }
