一、是什么
類(Class)是面向對象程序設計(OOP,Object-Oriented Programming)實現信息封裝的基礎
❝類是一種用戶定義的引用數據類型,也稱類類型
❞
傳統的面向對象語言基本都是基於類的,JavaScript
基於原型的方式讓開發者多了很多理解成本
在 ES6
之后,JavaScript
擁有了 class
關鍵字,雖然本質依然是構造函數,但是使用起來已經方便了許多
但是JavaScript
的class
依然有一些特性還沒有加入,比如修飾符和抽象類
TypeScript
的 class
支持面向對象的所有特性,比如 類、接口等
二、使用方式
定義類的關鍵字為 class
,后面緊跟類名,類可以包含以下幾個模塊(類的數據成員):
- 「字段」 :字段是類里面聲明的變量。字段表示對象的有關數據。
- 「構造函數」:類實例化時調用,可以為類的對象分配內存。
- 「方法」:方法為對象要執行的操作
如下例子:
class Car {
// 字段
engine:string;
// 構造函數
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("發動機為 : "+this.engine)
}
}
繼承
類的繼承使用過extends
的關鍵字
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
Dog
是一個 派生類,它派生自 Animal
基類,派生類通常被稱作子類,基類通常被稱作 超類
Dog
類繼承了Animal
類,因此實例dog
也能夠使用Animal
類move
方法
同樣,類繼承后,子類可以對父類的方法重新定義,這個過程稱之為方法的重寫,通過super
關鍵字是對父類的直接引用,該關鍵字可以引用父類的屬性和方法,如下:
class PrinterClass {
doPrint():void {
console.log("父類的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 調用父類的函數
console.log("子類的 doPrint()方法。")
}
}
修飾符
可以看到,上述的形式跟ES6
十分的相似,typescript
在此基礎上添加了三種修飾符:
- 公共 public:可以自由的訪問類程序里定義的成員
- 私有 private:只能夠在該類的內部進行訪問
- 受保護 protect:除了在該類的內部可以訪問,還可以在子類中仍然可以訪問
私有修飾符
只能夠在該類的內部進行訪問,實例對象並不能夠訪問
並且繼承該類的子類並不能訪問,如下圖所示:
受保護修飾符
跟私有修飾符很相似,實例對象同樣不能訪問受保護的屬性,如下:
有一點不同的是 protected
成員在子類中仍然可以訪問
除了上述修飾符之外,還有只讀「修飾符」
只讀修飾符
通過readonly
關鍵字進行聲明,只讀屬性必須在聲明時或構造函數里被初始化,如下:
除了實例屬性之外,同樣存在靜態屬性
靜態屬性
這些屬性存在於類本身上面而不是類的實例上,通過static
進行定義,訪問這些屬性需要通過 類型.靜態屬性 的這種形式訪問,如下所示:
class Square {
static width = '100px'
}
console.log(Square.width) // 100px
上述的類都能發現一個特點就是,都能夠被實例化,在 typescript
中,還存在一種抽象類
抽象類
抽象類做為其它派生類的基類使用,它們一般不會直接被實例化,不同於接口,抽象類可以包含成員的實現細節
abstract
關鍵字是用於定義抽象類和在抽象類內部定義抽象方法,如下所示:
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}
這種類並不能被實例化,通常需要我們創建子類去繼承,如下:
class Cat extends Animal {
makeSound() {
console.log('miao miao')
}
}
const cat = new Cat()
cat.makeSound() // miao miao
cat.move() // roaming the earch...
三、應用場景
除了日常借助類的特性完成日常業務代碼,還可以將類(class)也可以作為接口,尤其在 React
工程中是很常用的,如下:
export default class Carousel extends React.Component<Props, State> {}
由於組件需要傳入 props
的類型 Props
,同時有需要設置默認 props
即 defaultProps
,這時候更加適合使用class
作為接口
先聲明一個類,這個類包含組件 props
所需的類型和初始值:
// props的類型
export default class Props {
public children: Array<React.ReactElement<any>> | React.ReactElement<any> | never[] = []
public speed: number = 500
public height: number = 160
public animation: string = 'easeInOutQuad'
public isAuto: boolean = true
public autoPlayInterval: number = 4500
public afterChange: () => {}
public beforeChange: () => {}
public selesctedColor: string
public showDots: boolean = true
}
當我們需要傳入 props
類型的時候直接將 Props
作為接口傳入,此時 Props
的作用就是接口,而當需要我們設置defaultProps
初始值的時候,我們只需要:
public static defaultProps = new Props()
Props
的實例就是 defaultProps
的初始值,這就是 class
作為接口的實際應用,我們用一個 class
起到了接口和設置初始值兩個作用,方便統一管理,減少了代碼量