泛型
軟件工程中,我們不僅要創建一致的定義良好的API,同時也要考慮可重用性。 組件不僅能夠支持當前的數據類型,同時也能支持未來的數據類型,這在創建大型系統時爲你提供了十分靈活的功能。
在像C#和Java這樣的語言中,可以使用泛型
來創建可重用的組件,一個組件可以支持多種類型的數據。 這樣用戶就可以以自己的數據類型來使用組件。
泛型的特點
- 支持多種類型的數據(不特定的數據類型)。
- 傳入的類型與返回的類型應該是相同的。
- 使用類型變量且指標是類型,不是值。
- 泛型的類型取決於調用的時候傳入的參數類型。
- 對不特定類型數據的校驗。
不用泛型的話,這個函數可能是下面這樣:
function identity(arg: number): number {
return arg;
}
或者,我們使用any
類型來定義函數:
function identity(arg: any): any {
return arg;
}
這裏存在一個問題,就是如果返回值是any會導致這個函數可以接收任何類型的arg
參數,即any放棄了類型檢查,這樣就丟失了一些信息:傳入的類型與返回的類型應該是相同的。如果我們傳入一個數字,我們只知道任何類型的值都有可能被返回。
因此,我們需要一種方法使返回值的類型與傳入參數的類型是相同的。 這裏,我們使用了 類型變量,它是一種特殊的變量,只用於表示類型而不是值。
function identity<T>(arg: T): T {
return arg;
}
泛型的兩種使用
定義了泛型函數後,可以用兩種方法使用:
- 傳入所有的參數,包含類型參數:
let output = identity<string>("myString"); // type of output will be 'string'
這裏我們明確的指定了T
是string
類型,並做爲一個參數傳給函數,使用了<>
括起來而不是()
。
2.利用了類型推論 -- 即編譯器會根據傳入的參數自動地幫助我們確定T的類型
let output = identity("myString"); // type of output will be 'string'
泛型類
class MinClass<T>{
public list:T[] = [];
add(value:T):void{
list.push(value);
}
min():T{
let minValue = list[0];
for(var i = 0;i<this.list.length;i;i++){
if(minNum>this.list[i]){
minNum = this.list[i];
}
}
}
}
var m1 = new MinClass<number>(); //實例化類,並且規定類的T(泛型)代表number
m1.add(12);
m1.add(3);
m1.add(9);
alert(m1.min());//3
var m2 = new MinClass<string>(); //實例化類,並且規定類的T(泛型)代表string
m2.add(c);
m2.add(a);
m2.add(b);
alert(m2.min());//a
泛型接口
首先定義一個函數類型接口
//定義一個非泛型的函數類型接口
interface ConfigFn{
(value1:string,value2:string):string;
}
var setData:Config = function(value1:string,value2:string):string{
return value1+value2;
}
setData('name','zsf');
很明顯這種函數類型藉口函數的傳入參數只能是string
所以爲了解決以上問題,引入泛型接口:
第一種定義泛型接口的方法:
//定義一個泛型函數類型的接口
interface ConfigFn{
<T>(value:T):T;
}
var getData:ConfigFn = function(value:T):T{
return value;
}
getData<string>('zsf');
getData<number>(123);
第二種定義泛型接口的方法:
//定義一個泛型函數類型的接口
interface ConfigFn<T>{
(value:T):T;
}
var getData:ConfigFn<T> = function(value:T):T{
return value;
}
var mygetData1:ConfigFn<string>=getData;
mygetData1:ConfigFn<string>(‘20’);
var mygetData2:ConfigFn<number>=getData;
mygetData2:ConfigFn<string>(20);
把類作爲參數類型的泛型類
- 定義一個類
- 把類作爲參數來約束傳入的類型
/*
定義一個User的類,這個類的作用就是映射數據庫字段
讓後定義一個mysqlDb的類,這個類用於操作數據庫
然後把User類作爲參數傳到MysqlDb中
*/
class User{
username:string | undefined;
password:string | undefined;
}
class MysqlDb{
//用User類來檢驗傳入的對象的合法性
add(user:User):boolean{
console.log(user);
return true;
}
}
var u = new User();
u.username = 'wj';
u.password = '我最帥';
var Db = new MysqlDb();
Db.add(u);
此時User 對象能夠順利存入,但是如果 要傳個其他類型的對象,比如說要傳一個文章類型的對象,那MysqlDb 就要重新定義數據類型,很顯然,這樣做不滿足泛型,所以要重新定義Mysql類。
class MysqlDb<T>{
//用User類來檢驗傳入的對象的合法性
add(info:T):boolean{
console.log(info);
return true;
}
}
class User{
username:string | undefined;
password:string | undefined;
}
var u = new User();
u.username = 'wj';
u.password = '我最帥';
var Db = new MysqlDb<User>();
Db.add(u);
class ArticleCate{
title:string | undefined;
desc:string | undefined;
status:number | undefined;
constructor(params:{
title:string | undefined,
desc:string | undefined,
status?:number | undefined
}){
this.title = title;
this.desc = desc;
this.status = status;
}
}
var at = new ArticleCate({
title:'武俠',
desc:'張三丰成神之路'
});
var aDb = new MysqlDb<ArticleCate>();
aDb.add(at);