類
介紹
傳統(tǒng)的JavaScript程序使用函數(shù)和基于原型的繼承來(lái)創(chuàng)建面向?qū)ο蟮念?,在es6中,JavaScript程序員能夠使用基于類的面向?qū)ο蟮姆绞?,通過(guò)引入class關(guān)鍵字,表示定義一個(gè)類。TypeScript中允許開發(fā)者使用這些特性。
類的定義
其實(shí)typescript中定義類的方法與ES6相同,在ES6的基礎(chǔ)上,加了類型檢查。
//es6中定義類的方法:
class Person {
constructor(name){
this.name = name;
}
run() {
console.log(this.name);
}
}
//ts中定義類的方法
class Person {
public name:string; // public關(guān)鍵字可省略
constructor(name:string){ //構(gòu)造函數(shù) 實(shí)例化類的時(shí)候觸發(fā)的方法
this.name = name;
}
run():void {
console.log(this.name);
}
}
// 執(zhí)行方法
var p=new Person('張三');
p.run()
繼承
在TypeScript中,我們可以使用常用的面向?qū)ο竽J?。可使用繼承(關(guān)鍵字extends、super)來(lái)擴(kuò)展現(xiàn)有的類。
class Person {
public name:string; // public關(guān)鍵字可省略
constructor(name:string){ //構(gòu)造函數(shù) 實(shí)例化類的時(shí)候觸發(fā)的方法
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name); // 初始化父類的構(gòu)造函數(shù),必須調(diào)用super();
}
}
var w=new Web('張三');
w.run()
上述例子展示了基本的繼承:類從基類中繼承了屬性和方法。這里, Web是一個(gè)派生類,它派生自Person基類,通過(guò)extends關(guān)鍵字。派生類通常被稱作子類,基類通常被稱作超類.
因?yàn)?code>Web繼承了Person的功能,因此Web的實(shí)例能夠執(zhí)行run方法。
當(dāng)子類中定義的方法和父類一致時(shí),會(huì)執(zhí)行子類中的方法,這是
原型鏈的查找規(guī)則。
類中的修飾符(public、protected、private)
public :公有,在當(dāng)前類里面、 子類 、類外面都可以訪問(wèn);
protected:保護(hù)類型,在當(dāng)前類里面、子類里面可以訪問(wèn) ,在類外部沒(méi)法訪問(wèn)
private :私有 ,在當(dāng)前類里面可以訪問(wèn),子類、類外部都沒(méi)法訪問(wèn)
默認(rèn)為public
在TypeScript中,成員默認(rèn)為public,也可以明確將一個(gè)成員標(biāo)記為public。上面的例子也可這么寫:
class Person {
public name:string; // public關(guān)鍵字可省略
public constructor(name:string){ //構(gòu)造函數(shù) 實(shí)例化類的時(shí)候觸發(fā)的方法
this.name = name;
}
public run():void {
console.log(this.name);
}
}
var p=new Person('張三');
p.run()
理解protected
protected類型的成員在當(dāng)前類和子類中都可以訪問(wèn),但不能在類外部訪問(wèn)。
// 類外部無(wú)法訪問(wèn)保護(hù)類型的屬性
class Person {
protected name:string;
constructor(name:string){
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name); // 這里仍可以訪問(wèn)name,因?yàn)閣eb是由person類派生來(lái)的
}
}
var p=new Person('張三');
p.name; // error 不能在類外部使用protected類型變量或方法
注意:當(dāng)派生類構(gòu)造函數(shù)被標(biāo)記為protected。這意味著這個(gè)類不能在包含它的類外被實(shí)例化,但是能被繼承。
理解private
當(dāng)成員被 標(biāo)記成private時(shí),它就不能在聲明它的類的外部訪問(wèn)。
class Person {
private name:string;
constructor(name:string){
this.name = name;
}
run():void {
console.log(this.name);
}
}
class Web extends Person{
constructor(name:string){
super(name);
}
work():void {
console.log(this.name); // error 私有變量不能在子類中使用
}
}
var p=new Person('張三');
p.name; // error 私有變量不能在類外部使用
靜態(tài)屬性 靜態(tài)方法
靜態(tài)屬性及方法存在于類本身而不是類的實(shí)例上。使用static關(guān)鍵字定義,如果實(shí)例對(duì)象想訪問(wèn)靜態(tài)屬性,需在屬性age前加類名Person,如下例:
class Person {
name:string;
static age:number = 20;
constructor(name:string){
this.name = name;
}
static run():void {
console.log(this.name);
}
work():void{
console.log(Person.age); // 訪問(wèn)靜態(tài)屬性,必須使用類Person調(diào)用
}
}
var p = new Person('張三');
p.run(); // error 訪問(wèn)靜態(tài)方法,必須使用類調(diào)用
Person.run(); // right
抽象類 多態(tài)
抽象類作為其他派生類的基類,一般不會(huì)直接被實(shí)例化。使用abstract關(guān)鍵字定義抽象類和抽象方法。
抽象類中的抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)。abstract抽象方法只能放在抽象類里面。
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any; //抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)。
run(){
console.log('其他方法可以不實(shí)現(xiàn)')
}
}
// var a=new Animal() /*錯(cuò)誤的寫法*/
class Dog extends Animal{
//抽象類的子類必須實(shí)現(xiàn)抽象類里面的抽象方法
constructor(name:any){
super(name)
}
eat(){
console.log(this.name+'吃糧食')
}
}
var d=new Dog('小花花');
d.eat();
多態(tài):父類定義一個(gè)方法不去實(shí)現(xiàn),讓繼承它的子類去實(shí)現(xiàn) 每一個(gè)子類有不同的表現(xiàn)。
class Animal {
name:string;
constructor(name:string) {
this.name=name;
}
eat(){ //具體吃什么 不知道 ?繼承它的子類去實(shí)現(xiàn) ,每一個(gè)子類的表現(xiàn)不一樣
console.log('吃的方法')
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃糧食'
}
}
class Cat extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃老鼠'
}
}
var d = new Dog('小狗');
var c = new Cat('小花');
d.eat(); // 小狗吃糧食
c.eat(); // 小花吃老鼠
// 對(duì)于同一個(gè)方法每個(gè)子類實(shí)例有不同的表現(xiàn)
接口
接口的作用:在面向?qū)ο蟮木幊讨校涌谑且环N規(guī)范的定義,它定義了行為和動(dòng)作的規(guī)范,在程序設(shè)計(jì)里面,接口起到一種限制和規(guī)范的作用。接口定義了某一批類所需要遵守的規(guī)范,接口不關(guān)心這些類的內(nèi)部狀態(tài)數(shù)據(jù),也不關(guān)心這些類里方法的實(shí)現(xiàn)細(xì)節(jié),它只規(guī)定這批類里必須提供某些方法,提供這些方法的類就可以滿足實(shí)際需要。 typescript中的接口類似于java,同時(shí)還增加了更靈活的接口類型,包括屬性、函數(shù)、可索引和類等。
屬性類接口
ts中當(dāng)自定義方法需對(duì)傳入的參數(shù)進(jìn)行約束時(shí),我們可以這樣定義:
約束傳入的參數(shù)必須是對(duì)象,并且有l(wèi)abel屬性
function printLabel(labelInfo:{label:string}):void {
console.log('printLabel');
}
printLabel('hahah'); //錯(cuò)誤寫法
printLabel({name:'張三'}); //錯(cuò)誤的寫法
printLabel({label:'張三'}); //正確的寫法
當(dāng)需要對(duì)批量方法傳入的參數(shù)進(jìn)行更新時(shí),可引入接口:行為和動(dòng)作的規(guī)范,對(duì)批量方法進(jìn)行約束.
interface FullName{
firstName:string; //注意;結(jié)束
secondName:string;
}
function printName(name:FullName){
// 必須傳入對(duì)象 firstName secondName
console.log(name.firstName+'--'+name.secondName);
}
printName('1213'); //錯(cuò)誤
var obj={ /*傳入的參數(shù)必須包含 firstName secondName*/
age:20,
firstName:'張',
secondName:'三'
};
printName(obj); // 輸出“張--三”
當(dāng)接口里的屬性不全都是必需的,在某些條件下存在,或者根本不存在時(shí),可在可選屬性名字定義的后面加?符號(hào)
函數(shù)類型接口
函數(shù)類型接口:對(duì)方法傳入的參數(shù)以及返回值進(jìn)行約束
interface encrypt {
(key:string, value:string):string;
}
var md5:encrypt = function(key:string, value:string):string {
return key+value;
}
console.log(md5('name', 'zhangsan'));
對(duì)于函數(shù)類型的類型檢查來(lái)說(shuō),函數(shù)的參數(shù)名不需要與接口定義的名字相匹配,比如用下面的代碼重寫上面的例子:
var md5:encrypt = function(source:string, src:string):string {
return source+src;
}
類類型接口
對(duì)類的約束,和抽象類有點(diǎn)相似
在C#或Java中,接口通常是用來(lái)定義一個(gè)類的公共部分,然后創(chuàng)建一個(gè)類,通過(guò)implements關(guān)鍵字去實(shí)現(xiàn)接口。
在接口中描述方法,在類里實(shí)現(xiàn)它。
interface Animal{
name:string;
eat(str:string):void;
}
class Dog implements Animal{
name:string;
constructor(name:string){
this.name=name;
}
eat(){
console.log(this.name+'吃糧食')
}
}
var d=new Dog('小黑');
d.eat();
可索引接口
可索引接口:是對(duì)數(shù)組、對(duì)象的約束。不太常用
//可索引接口 對(duì)數(shù)組的約束
interface UserArr{
[index:number]:string
}
var arr:UserArr=['aaa','bbb'];
console.log(arr[0]);
var arr:UserArr=[123,'bbb']; /*錯(cuò)誤,索引的值只能是string*/
console.log(arr[0]);
//可索引接口 對(duì)對(duì)象的約束
// 索引為string類型,值也為string類型
interface UserObj{
[index:string]:string
}
var arr:UserObj={name:'張三'};
擴(kuò)展接口:接口可以繼承接口
interface Animal{
eat():void;
}
interface Person extends Animal{
work():void;
}
class Programmer{
public name:string;
constructor(name:string){
this.name=name;
}
coding(code:string){
console.log(this.name+code)
}
}
class Web extends Programmer implements Person{
constructor(name:string){
super(name)
}
eat(){
console.log(this.name+'喜歡吃饅頭')
}
work(){
console.log(this.name+'寫代碼');
}
}
var w=new Web('小李');
w.eat();
w.coding('寫ts代碼');
在上面例子中,定義了兩個(gè)接口Animal和Person ,其中Person繼承自Animal,又定義programmer類,具有name屬性和coding方法,定義的Web類繼承自Programmer并實(shí)現(xiàn)了Person接口,因此Web實(shí)例也有name屬性和Animal、Person接口的方法eat、work、coding
上一篇TypeScript基礎(chǔ)入門(三)主要介紹ts中的函數(shù)