OOP(Object-Oriented Programming,物件導向程式設計)是一種程式設計範式或方法論,以物件為核心,將資料和與資料相關的操作封裝在一起,以建立可重複使用和易於維護的程式碼。在物件導向程式設計中,程式被組織為一組相互關聯的物件,每個物件代表現實世界中的一個實體,具有屬性和方法。
類別是物件導向程式設計(Object-Oriented Programming,OOP)的核心概念之一,它提供了一種建立物件的藍圖。類別定義了物件的屬性和方法,允許我們將相關的程式碼組織在一起,並建立具有相似特性的多個物件。在 TypeScript 中,類別是一種強型別的結構,可以明確指定屬性和方法的型別。
在 TypeScript 中,要定義一個類別,我們使用 class
關鍵字,後面跟著類別名稱。
class Department {
// 屬性
name: string;
// 建構函式
constructor(name: string) {
this.name = name;
}
// 方法
describe(this: Department) {
console.log(`部門:${this.name}`);
}
}
要建立類別的物件,我們使用 new
關鍵字,後面跟著類別名稱,並傳遞建構函式所需的參數。
class Department {
name: string;
constructor(name: string) {
this.name = name;
}
describe() {
console.log(`部門:${this.name}`);
}
}
const engineering = new Department('工程部');
建構函式是類別的一部分,它在建立物件時被呼叫,用於初始化物件的屬性。在建構函式內部,我們使用 this
關鍵字來存取物件的屬性,並將參數的值分配給物件的對應屬性。
class Department {
name: string;
constructor(name: string) {
this.name = name;
}
describe() {
console.log(`部門:${this.name}`);
}
}
const engineering = new Department('工程部');
engineering.describe(); // 部門:工程部
當我們有一個 personCopy
的新物件,只有 sayHello
方法並指向原本的 perosn
物件,看看有什麼變化。
class Department {
name: string;
constructor(name: string) {
this.name = name;
}
describe() {
console.log(`部門:${this.name}`);
}
}
const engineering = new Department('工程部');
engineering.describe(); // 部門:工程部
const engineeringCopy = {
describe: engineering.describe,
};
engineeringCopy.describe(); // 部門:undefined
此時,TypeScript 編譯並不會報錯,但在運行時,我們可以看到輸出的值是 undefined
,這是因為 engineeringCopy.describe
的 this
是指向自己,它是一個偽物件,本身沒有 name
屬性,最後,我們得到的輸出是 undefined
。
在 describe
方法中,使用 this
參數指定該方法應該被調用在屬於 Department
類別的物件上。這樣一來,在方法內我們可以安全存取 this
物件的屬性。
class Department {
name: string;
constructor(name: string) {
this.name = name;
}
describe(this: Department) {
console.log(`部門:${this.name}`);
}
}
const engineering = new Department('工程部');
engineering.describe(); // 部門:工程部
// 自己的物件新增一個 name 屬性,否則 TypeScript 會報錯
const engineeringCopy = {
name: '會計部',
describe: engineering.describe,
};
engineeringCopy.describe(); // 部門:會計部
public
、private
和 protected
是 TypeScript 特有的功能,用於控制類別的屬性和方法可存取性。
屬性或方法為是公有的,表示可以從任何地方被存取,預設所有的屬性和方法都是 public
,可以省略。
class Department {
name: string;
employees: string[] = [];
constructor(name: string) {
this.name = name;
}
addEmployee(employee: string) {
this.employees.push(employee);
}
printEmployeeInformation() {
console.log(this.employees.length); // 2
console.log(this.employees); // ['肉鬆', '傑尼龜']
}
}
const engineering = new Department('工程部');
engineering.addEmployee('肉鬆'); // 可以存取
engineering.addEmployee('傑尼龜'); // 可以存取
engineering.printEmployeeInformation(); // 可以存取
屬性或方法是私有的,表示只能在類別內部存取,無法從類別外部存取。
class Department {
name: string;
private employees: string[] = [];
constructor(name: string) {
this.name = name;
}
addEmployee(employee: string) {
this.employees.push(employee);
}
printEmployeeInformation() {
console.log(this.employees.length);
console.log(this.employees);
}
}
const engineering = new Department('工程部');
engineering.addEmployee('肉鬆'); // 可以存取
engineering.addEmployee('傑尼龜'); // 可以存取
engineering.employees[2] = '小明'; // TypeScript 報錯,'employees' 是私用屬性,只可從類別 'Department' 中存取
engineering.printEmployeeInformation(); // 可以存取
屬性或方法是受保護的,表示只能在類別內部和子類別存取,無法從類別外部存取。
class Department {
name: string;
protected employees: string[] = [];
constructor(name: string) {
this.name = name;
}
addEmployee(employee: string) {
this.employees.push(employee);
}
printEmployeeInformation() {
console.log(this.employees.length);
console.log(this.employees);
}
}
class RDDepartment extends Department {
constructor(name: string) {
super(name);
}
addRD(employee: string) {
// 因為 employees 是 protected,所以可以在子類中存取
this.employees.push(employee);
}
}
const rd = new RDDepartment('工程部');
rd.addEmployee('肉鬆'); // 可以存取
rd.addRD('傑尼龜'); // 可以存取
rd.employees[2] = '小明'; // TypeScript 報錯,'employees' 是受保護屬性,只可從類別 'Department' 及其子類別中存取
rd.printEmployeeInformation(); // 可以存取
在 TypeScript 中,我們可以使用 extends
關鍵字實現繼承,這允許子類別繼承父類別的屬性和方法。子類別可以使用 super
關鍵字來調用父類別的建構函式或方法。
class Department {
name: string;
employees: string[] = [];
constructor(name: string) {
this.name = name;
}
addEmployee(employee: string) {
this.employees.push(employee);
}
printEmployeeInformation() {
console.log(this.employees.length);
console.log(this.employees);
}
}
class RDDepartment extends Department {
constructor(name: string, employee: string[]) {
super(name); // // 使用 super 調用父類別的建構函式
this.employees = employee
}
addRD(employee: string) {
this.employees.push(employee);
}
}
const rd = new RDDepartment('工程部', ['肉鬆', '傑尼龜']);
rd.printEmployeeInformation();
在 TypeScript 中,我們可以使用 get
和 set
控制類別的屬性的讀取和賦值。
class Person {
constructor(name) {
this.name = name;
}
get name() {
return '小明';
}
set name(value) {
console.log('setter: ' + value);
}
}
let person = new Person('肉鬆'); // setter: 肉鬆
person.name = '傑尼龜'; // setter: 傑尼龜
console.log(person.name); // 小明
在 TypeScript 中,我們可以使用 static
關鍵字定義靜態屬性或方法。靜態屬性或方法不需要物件類別就可以存取屬性或方法。
class Department {
static year = 2023;
constructor() {
console.log(this.year); // TypeScript 報錯,屬性 'year' 不存在於類型 'Department' 上
console.log(Department.year); // 2023
}
}
console.log(Department.year); // 2023
class Department {
static createEmployee(name: string) {
return {
name,
};
}
}
const employee = Department.createEmployee('肉鬆'); // 可以直接調用靜態方法
console.log(employee); // {name: '肉鬆'}
在 TypeScript 中,我們可以使用 abstract
關鍵字定義抽象屬性和方法。抽象類別是一個不能被物件化的類別,通常用來定義一個共同的介面,而具體實現留給子類別。
abstract class Department {
static year: number = 2023;
constructor() {
console.log(Department.year); // 2023
}
// 抽象類別中的抽象方法,需要在子類別中實現
abstract getEmployeeInfo(name: string): void;
}
class RDDepartment extends Department {
getEmployeeInfo(name: string) {
return {
name,
yearJoined: Department.year,
};
}
}
class ITDepartment extends Department {
getEmployeeInfo(name: string) {
return {
name,
yearJoined: Department.year,
};
}
}
const rd = new RDDepartment();
console.log(rd.getEmployeeInfo('肉鬆')); // {name: '肉鬆', yearJoined: 2023}
const it = new ITDepartment();
console.log(it.getEmployeeInfo('傑尼龜')); // {name: '傑尼龜', yearJoined: 2023}
class
關鍵字來定義一個類別。constructor
方法來初始化類別的屬性,這是在建立類別自動調用的特殊方法。this
參數指定該方法應該被調用在屬於哪個類別的物件上public
表示可以從任何地方被存取、private
表示只能在類別內部存取,無法從類別外部存取、protected
表示只能在類別內部和子類別存取,無法從類別外部存取。extends
關鍵字實現繼承,子類別可以使用 super
關鍵字來調用父類別的建構函式或方法。get
和 set
控制類別的屬性的讀取和賦值。static
關鍵字定義靜態屬性或方法,需要物件類別就可以存取屬性或方法。abstract
關鍵字定義抽象屬性和方法,具體需要在子類別實現。