總目錄
從C#到TypeScript - function
雖然TypeScript里有了類,但JavaScript的function
也還在,這也是和C#的不同所在。
C#里函數不能脫離類工作,但TypeScript的function
和JavaScript一樣,可以單獨工作。
函數類型
函數和C#一樣可以有名字,也可以是匿名函數,匿名函數有兩種寫法:
function checkLogin(name: string, pwd: string): boolean{
return true;
}
let checkLogin = (name: string, pwd: string) => {
return false;
}
let checkLogin = function(name: string, pwd: string){
return true;
}
前面文章寫變量聲明時有寫變量類型let str: string
,但上面其實都沒有把函數的類型真正寫出來,比如最后一個let checkLogin
里並沒有標明返回的類型。
如果要把函數做為參數或返回值的話如果沒有明確類型的話使用會很不方便,沒有智能提示,重構也不方便。
函數的返回類型其實就是由參數+返回類型構成,下面代碼的(name: string, pwd: string) => boolean
就是checkLogin的返回類型。
let checkLogin: (name: string, pwd: string) => boolean = function(name: string, pwd: string){
return true;
}
返回類型里的參數名不需要與真正的參數名一致,只需要類型一致即可。
當然,大部分情況下是不用寫這么復雜的返回類型的,前面文章有說過類型推論,TypeScript會根據上下文推論出返回值的類型。
函數參數
TypeScript的參數和JavaScript的參數不太一樣,調用JavaScript函數的參數可以多或少都可以,但TypeScript里函數需要確保傳入參數的個數和定義的一致。
同C#里的函數參數可以有默認值一樣,TypeScript也支持,並且還支持可空參數。
默認值只需要在參數后面寫上=
某值就可以,默認值參數可以在任意位置,不過在必須參數前面時,想用默認值的話需要傳undefined
。
可空參數和前面說的可空屬性一樣,參數名后加?
號,可空參數必須是在最后面。
function checkLogin(name: string, pwd: string, isAdmin: boolean = false, email?: string){
console.info(isAdmin);
}
checkLogin('brook'); // 編譯不了
checkLogin('brook', '123456'); // false
checkLogin('brook', '123456', undefined); // false
checkLogin('brook', '123456', false); // false
checkLogin('brook', '123456', true, 'brook@email.com'); // true
剩余參數
JavaScript里的參數本身是個數組,可以是任意個數且都可以在函數體內用arguments
來訪問。
TypeScript同樣可以通過剩余參數來支持,形式上類似於C#的param
。
剩余參數的格式是...restParam: string[]
。
function checkLogin(name: string, pwd: string, ...others: string[]){
console.info(others.join(' '));
}
checkLogin('brook', '123456', 'brook@email.com', `12800`); // brook@email.com 12800
this
this
在JavaScript里總是指向調用者,這點經常容易導致被坑,在ES6之前經常需要類似var self = this
來把this
保存下來。
ES6和TypeScript針對這點做了改進,使用箭頭函數可以把創建函數時的this
自動保存下來。
let permission = {
name: 'brook',
checkLogin: function() {
return function() {
console.info(this.name === 'brook');
}
}
};
permission.checkLogin()(); // 出錯, this為undefined
let permission = {
name: 'brook',
checkLogin: function() {
return () => {
console.info(this.name === 'brook');
}
}
};
permission.checkLogin()(); // 通過,因為用了箭頭函數
不過上面的this
還是有個缺點,得到的this
是any
類型,這樣重構起來會不方便,這時可以用this
參數來改進:
this
參數只是一種定義,使用時是不需要傳的。
interface Permission{
name: string;
checkLogin(this: Permission): ()=>void;
}
let permission: Permission = {
name: 'brook',
checkLogin: function(this: Permission) {
return () => {
console.info(this.name === 'brook'); //這里的this不是any,而是Permission
}
}
};
permission.checkLogin()();
這樣也倒逼着定義好類型,發揮TypeScript強類型的優勢。
泛型函數
同C#一樣支持泛型函數,寫法也差不多。
function deserialize<T>(content: string): T { }
function addItem<TKey, TValue>(key: TKey, value: TValue) { }
也支持泛型約束,C#用的是where T: object
,而TypeScript用的是extends Object
。
function deserialize<T extends Object>(content: string): T { }
泛型函數類型比普通函數類型在前面多了個<T>
,比如上面deserialize
。
let deserialize: <T>(content: string) => T;
但這樣如果做為參數就略顯復雜,可以用接口重構下:
function deserialize<T extends Object>(content: string): T { }
interface serializable<T> {
(content: string): T;
}
function parse<T>(s: serializable<T>){ }
parse(deserialize);