前言
今天來研究研究 TS 中 Class 的細節
Class 是什麼?
在TypeScript
(TS) 中,class
用於定義物件導向
程式設計中的類別
。與 JavaScript
相比,TypeScript
的 class
具有一些特別的功能和優點
- 靜態類型檢查
- 封裝和訪問修飾詞
- 建構函式和初始化器
- 繼承和多型
- 抽象類別和介面
- 存取器(Accessors)
特點 | 說明 |
---|---|
靜態類型檢查 | TypeScript 提供強大的型別檢查 ,可在類別的屬性 、方法 和建構函式 上聲明型別,以確保程式碼的正確性。 |
封裝和訪問修飾詞 | 使用訪問修飾詞(public 、private 、protected )來控制屬性和方法的可訪問性,確保只有適當的程式碼可以訪問和修改類別的內部狀態。 |
建構函式和初始化器 | 類別中的建構函式(constructor )在建立類別實例時被調用,可用於初始化屬性或執行其他必要的操作。 |
繼承和多型 | 類別可以透過繼承機制建立繼承關係,子類別可以繼承父類別的屬性和方法,並進行擴充和覆寫,提供程式碼的重用和組織的靈活性。 |
抽象類別和介面 | TypeScript 支援抽象類別和介面的定義。抽象類別不能被實例化 ,但可以作為其他類別的基類,而介面定義了一組合約,類別可以實現這些介面以確保符合特定的結構。 |
存取器(Accessors) | 使用 get 和 set 存取器來設置和獲取類別的屬性值 ,可對屬性的存取進行更多控制,例如執行額外的邏輯 或驗證 。 |
TypeScript 和 JavaScript 中 class 的差異
功能 | TypeScript (TS) | JavaScript (JS) |
---|---|---|
靜態型別檢查 | 支援靜態型別檢查,可在編譯時檢測並捕獲許多錯誤。 | 沒有內建的靜態型別檢查機制。 |
型別註解和型別推斷 | 可以聲明變數、函式和物件的型別,並且進行型別推斷。 | 可以聲明變數的型別,但沒有內建的型別推斷機制。 |
類別和模組 | 支援類別和模組的原生語法,可使用 class 和 module 關鍵字。 |
沒有內建的類別和模組語法,使用原型和函式進行物件導向編程。 |
介面和抽象類別 | 支援介面和抽象類別的定義,用於描述物件的結構和行為。 | 沒有內建的介面和抽象類別語法,通常使用原型和函式來實現相似的功能。 |
可選參數和預設參數 | 可以將函式的參數設置為可選的 ? 符號標記,並指定預設值。 |
可以模擬可選參數和預設參數,但沒有內建的語法支援。 |
存取修飾詞 | 支援存取修飾詞(public 、private 、protected )來控制屬性和方法的訪問權限。 |
沒有內建的存取修飾詞,所有屬性和方法都是公開的。 |
繼承和多型 | 支援類別之間的繼承關係,子類別可以繼承父類別的屬性和方法。 | 支援原型鏈繼承,但沒有內建的語法支援類別之間的繼承。 |
建構函式和初始化器 | 可以在類別中定義建構函式(constructor),用於初始化 |
使用方式
定義類的關鍵字為class
,後面緊跟類名,Class 可以包含以下幾個模塊(Class 的數據成員):
字段
: 字段是類裡面聲明的變量。字段表示對象的有關數據。構造函數
: 類實例化時調用,可以為類的對象分配內存。方法
: 方法為對像要執行的操作
1 | class Car { |
繼承
Class
的繼承使用過extends
的關鍵字
1 | class Animal { |
Dog
是一個派生類,它派生自 Animal
基類,派生類通常被稱作子類,基類通常被稱作超類
Dog
類繼承了 Animal 類,因此實例dog
也能夠使用 Animal 類 move 方法
同樣,類繼承後,子類
可以對父類
的方法重新定義,這個過程稱之為方法的重寫
,通過 super
關鍵字是對父類的直接引用,該關鍵字可以引用父類的屬性和方法
,如下:
1 | class PrinterClass { |
修飾詞
可以看到,上述的形式跟ES6
十分的相似,typescript
在此基礎上添加了三種修飾詞 :
公共public
:可以自由的訪問類程序裡定義的成員私有private
:只能夠在該類的內部進行訪問受保護protect
:除了在該類的內部可以訪問,還可以在子類中仍然可以訪問
私有修飾詞
只能夠在該類的內部進行訪問,實例對象並不能夠訪問
並且繼承該類的子類並不能訪問,如下圖所示:
受保護修飾詞
跟私有修飾詞很相似,實例對象同樣不能訪問受保護的屬性,如下:
有一點不同的是
protected
成員在子類中仍然可以訪問
除了上述修飾詞外,還有唯讀修飾詞
唯讀修飾詞
通過readonly
關鍵字進行聲明,唯讀屬性必須在聲明時
或構造函數
里被初始化,如下:
除了實體屬性 還有靜態屬性
靜態屬性
這些屬性存在於Class
本身上面而不是Class
的實例上,通過static
進行定義,訪問這些屬性需要通過類型
.靜態屬性的這種形式訪問,如下所示:
1 | class Square { |
上述的
Class
都能發現一個特點就是,都能夠被實例化
,在typescript
中,還存在一種抽像類
抽像類
抽像類
做為其它派生類的基類
使用,它們一般不會直接被實例化
,不同於接口,抽像類可以包含成員的實現細節
abstract
關鍵字是用於定義抽像類和在抽像類內部定義抽象方法,如下所示:
1 | abstract class Animal { |
這種類並不能被實例化,通常需要我們創建子類去繼承,如下:
1 | class Cat extends Animal { |
應用場景
除了日常藉助類的特性完成日常業務代碼,還可以將類(class)
也可以作為接口,尤其在 React 中是很常用的,如下:
1 | export default class Carousel extends React.Component<Props, State> {} |
由於組件需要傳入 props
的類型Props
,同時有需要設置默認 props
即defaultProps
,這時候更加適合使用class
作為接口
先聲明一個類,這個類包含組件 props
所需的類型和初始值:
1 | // props的类型 |
當我們需要傳入 props
類型的時候直接將 Props
作為接口傳入,此時 Props
的作用就是接口,而當需要我們設置defaultProps
初始值的時候,我們只需要:
1 | public static defaultProps = new Props() |
Props
的實例就是defaultProps
的初始值,
這就是 `class` 作為接口的實際應用,
我們用一個 `class` 起到了接口和設置初始值兩個作用,
方便統一管理,減少了代碼量