本文將會深入討論 TypeScript 中的面向對象編程相關的特性,包括:
-
類的定義和使用
-
繼承和多態
-
抽象類和接口
-
泛型和類型約束
-
裝飾器
類的定義和使用
在 TypeScript 中,我們可以使用 class 關鍵字來定義類:
class Person {
private name: string;
private age: number;
?
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
?
getName(): string {
return this.name;
}
?
getAge(): number {
return this.age;
}
}
?
const person = new Person('張三', 18);
?
console.log(person.getName()); // 輸出:張三
console.log(person.getAge()); // 輸出:18
在上述代碼中,我們定義了一個 Person 類,該類有兩個私有屬性 name 和 age,并且有一個構造函數用于初始化這兩個屬性。類中還有兩個公共方法 getName 和 getAge,用于獲取屬性值。在創建類的實例時,需要使用 new 關鍵字,并傳入構造函數所需的參數。
繼承和多態
繼承是面向對象編程中的重要概念,它可以用于復用代碼和構建類層次結構。在 TypeScript 中,我們可以使用 extends 關鍵字實現繼承:
class Animal {
protected name: string;
?
constructor(name: string) {
this.name = name;
}
?
move(distance: number = 0): void {
console.log(`${this.name} moved ${distance}m.`);
}
}
?
class Dog extends Animal {
bark(): void {
console.log('Woof! Woof!');
}
}
?
const dog = new Dog('旺財');
?
dog.move(10); // 輸出:旺財 moved 10m.
dog.bark(); // 輸出:Woof! Woof!
在上述代碼中,我們定義了一個 Animal 類,它有一個受保護的屬性 name 和一個公共方法 move,并且有一個默認值為 0 的參數 distance。Dog 類繼承自 Animal 類,并且有一個獨有的方法 bark。在創建 Dog 類的實例時,既可以使用從父類繼承的 move 方法,也可以使用自己獨有的 bark 方法,這就是多態。
抽象類和接口
抽象類和接口是面向對象編程中的兩個重要概念,它們分別用于描述類和對象的共性和特性。在 TypeScript 中,我們可以使用 abstract 關鍵字定義抽象類,并且使用 implements 關鍵字實現接口。
interface Animal {
name: string;
move(distance: number): void;
}
?
abstract class Shape {
abstract getArea(): number;
}
?
class Rectangle extends Shape {
private width: number;
private height: number;
?
constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}
?
getArea(): number {
return this.width * this.height;
}
}
?
class Elephant implements Animal {
name: string;
?
constructor(name: string) {
this.name = name;
}
?
move(distance: number): void {
console.log(`${this.name} moved ${distance}m.`);
}
}
?
const rect = new Rectangle(10, 20);
console.log(rect.getArea()); // 輸出:200
?
const elephant = new Elephant('大象');
elephant.move(50); // 輸出:大象 moved 50m.
在上述代碼中,我們使用 interface 關鍵字定義了一個 Animal 接口,它有兩個屬性 name 和 move。另外,我們使用 abstract 關鍵字定義了一個抽象類 Shape,該類有一個抽象方法 getArea,并且該類不能被實例化。Rectangle 類繼承自 Shape 類,并且實現了 getArea 方法。Elephant 類實現了 Animal 接口,并且重寫了 move 方法。在創建不同類型的對象時,分別使用了相應的類或接口,并進行了相應的操作。
泛型和類型約束
泛型是 TypeScript 中的一項強大特性,它可以讓函數和類接收任意類型的參數,在編譯時確定參數和返回值的類型。在 TypeScript 中,我們可以使用尖括號來表示泛型,并使用類型約束(extends)來限制泛型的類型。
function identity<T extends string | number>(arg: T): T {
return arg;
}
?
console.log(identity<string>('hello')); // 輸出:hello
console.log(identity<number>(123)); // 輸出:123
在上述代碼中,我們定義了一個泛型函數 identity,它接收一個類型為 T 的參數 arg,并將該參數原封不動地返回。為了限制 T 的類型,我們使用了類型約束 extends,限制 T 只能是 string 或 number 類型。在調用函數時,使用尖括號來指定泛型的具體類型。
裝飾器
裝飾器是 TypeScript 中的一個實驗性特性,它可以用于在編譯時修改類和方法的行為。在 TypeScript 中,我們可以使用 @decorator 的形式來應用裝飾器,其中 decorator 是一個函數。
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
?
descriptor.value = function (...args: any[]) {
console.log(`調用 ${propertyKey} 方法`);
const result = method.apply(this, args);
console.log(`返回值為 ${result}`);
return result;
}
?
return descriptor;
}
?
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
?
const calculator = new Calculator();
console.log(calculator.add(1, 2)); // 輸出:調用 add 方法,返回值為 3
在上述代碼中,我們定義了一個 log 裝飾器函數,該函數接收三個參數:類的原型對象 target、方法名 propertyKey 和方法描述符 descriptor。在裝飾器函數中,我們修改了方法的行為,在方法執行前打印了一句日志,方法執行后打印了返回值,并返回修改后的方法描述符。另外,我們使用裝飾器 @log 來應用裝飾器函數,該裝飾器應用于類的 add 方法上。在創建 Calculator 類的實例時,調用 add 方法并輸出結果,可以看到已經使用了裝飾器修改了方法的行為。
結論
TypeScript 中的面向對象編程相關的特性比較多,其中包括類的定義和使用、繼承和多態、抽象類和接口、泛型和類型約束、裝飾器等。這些特性可以讓開發者更加方便地進行面向對象編程,并且可以使得代碼更加具有可讀性、可維護性和可擴展性。在使用這些特性時,需要遵循 TypeScript 的類型約束和面向對象編程的思想,并根據項目需求進行選擇和應用。