---
# System prepended metadata

title: 物件導向程式設計Object-oriented Programming (OOP)
tags: [物件導向, TypeScript]

---

# 物件導向程式設計Object-oriented Programming (OOP)
###### tags: `物件導向` `TypeScript`
> [name=Potter]
> [time=Wed, Sep 14, 2022 10:42 AM]
>  學習並理解中，有錯誤麻煩幫忙指出 :+1: 

---
:::spoiler 本篇目錄 :+1::+1::+1:
[TOC]
:::


## 物件導向 Object-oriented(OO)
物件導向暱稱為oo，是電腦科學領域中的一種程式設計方式。
透過**類別 (class)** 的**函式建構式 (function constructor)** 可以產生**物件實例 (object instance)** ，而這個類別產生物件實例的過程稱作**實例化 (instantiation)**。

JavaScript 中使用一種名為 **建構式函式 (constructor functions)** 的函式來定義物件和他們的特色，ES6 之後推出 **class 語法糖** 來建立建構式函式。

### 基本概念 : 
> 5、6、7 點為 TypeScript 幫忙補上因為 JavaScript 是弱型別語言而有的問題。

### 1. 類別(Class)
定義一件事物的抽象特點，包含他的屬性和方法。
類別相當於設計藍圖，其中我們可以定義這張藍圖抽象的內容 (屬性、方法)。
可能包括:
 - 屬性 : 需要記憶的資訊。
 - 方法 : 能夠提供的服務。
 - 建構子 (constructor) : 程式執行時第一個去執行的方法，常用於設定程式初始狀態。使用 new 產生實例的時候，會自動呼叫。
```javascript=
class Person {
    constructor(name, interests) {
        this.name = name;
        this.interests = interests;
    }
    
    greeting() {
        console.log(`Hi I'm ${this.name}`);
    }
}
```
### 2. 物件(Object)
類別的實例 ( 透過==new==產生，會自動呼叫建構函式 )，可以由同一個類別去創建許多不同的實例，且這些實例的資料彼此之間互相不影響，都是獨立的。
```javascript=
const potter = new Person('Potter', 'computer science');
const andy = new Person('Andy', 'sleep');

// potter 物件跟 andy 物件有各自的名字(資料)，由同類別所建立的獨立物件且互不影響。
```

### 3. 物件導向的三大特性:
**3.1 封裝(Encapsulation)**
   一個抽象(abstract)的概念，物件內部資料隱藏，只透過物件本身提供的介面 (interface) 取得物件內部屬性或方法，只需要理解外在，不需要理解內部的構造。
   
**3.2 繼承(Inhertitance)**
   繼承者可以繼承被繼承者的屬性和方法，也能新增自己特有的屬性和方法。
   
**3.3 多型(Polymorphism)**
   簡單來說就是相同名稱的方法(Method)，**多個相同名稱的方法，傳入不同的參數，會執行不同的敘述** 包含多載 (Overloading) 和複寫 (Overriding)
   父類別可透過子類別衍伸成多種形態，而父類別為子類別的通用型態。
   
 - **多載(Overloading)**
   只要==方法的參數型態或數目不同，則**允許多個相同名稱**的方法存在==。但要注意多載並不包含回傳型態不同，也就是如果方法的名稱相同，參數型態及數目相同，而只有回傳型態不同，仍有命名衝突的錯誤。
   此為 Java 語言的範例 :
   ![](https://i.imgur.com/kVZvHT9.png)
 - **複寫(Overriding)**
   子類別可以複寫父類別的方法內容，使其擁有不同於父類別的行為。
   簡單來說就是改寫她的方法 (Method)。
      
### 4. 存取器 (getter & setter)
用以改變屬性的讀取和賦值行為。

### 5. 修飾符 (Modifiers)
修飾符是一些關鍵字，用於限定成員或型別的性質。比如==public==表示公有屬性或方法。

### 6. 抽象類別 (Abstract Class)
抽象類別是供其他類別繼承的基底類別，抽象類別不允許被實例化。
抽象類別中的抽象方法必須在子類別中被實現。
可以當作被拿來繼承使用的類別。

### 7. 介面 (Interface)
不同類別之間公有的屬性或方法，可以抽象成一個介面。介面可以被類別實現(implements)。一個類別只能繼承自另一個類別，但是可以實現多個介面。

---

# ES6 中類別的用法 :+1: 

## 屬性和方法
使用==class== 定義類別，使用==constructor== 定義建構函式。
透過==new== 產生新實例的時候，會自動呼叫建構函式。
```javascript=
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    sayHi() {
        return `My name is ${this.name}`;
    }
}

let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
```

## 類別的繼承
使用==extends== 關鍵字實現繼承，子類別中使用==super== 關鍵字來呼叫父類別的建構函式和方法。
```javascript=
class Cat extends Animal {
    constructor(name) {
        super(name); // 呼叫父類別的 constructor(name)
        console.log(this.name);
    }
    
    sayHi() {
        return 'Meow, ' + super.sayHi(); // 呼叫父類別的 sayHi()
    }
}

let c = new Cat('Tom'); // Tom
console.log(c.sayHi()); // Meow, My name is Tom
```

## 存取器
使用 getter 和 setter 可以改變屬性的賦值和讀取行為:
```javascript=
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    get name() {
        return 'Jack';
    }
    
    set name(value) {
        console.log('setter: ' + value);
    }
}

let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack
```

## 靜態方法
使用==static== 修飾符修飾的方法稱為靜態方法，他們不需要實例化，而是直接透過==類別==來呼叫:
```javascript=
class Animal {
    // 不會被實例化，所以物件實例不會有這個方法，只有類別有這個靜態方法能使用。
    static isAnimal(a) {
        return a instanceof Animal;
    }
}

let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
```

# ES7 中類別的用法 :+1: 
## 實例屬性
ES6 中實例的屬性只能透過建構函式中的 ==this.xxx== 來定義，ES7 提案中可以直接在類別裡面定義:
```javascript=
class Animal {
    name = 'Jack';
    
    constructor() {
        // ...
    }
}

let a = new Animal();
console.log(a.name); // Jack
```

## 靜態屬性
ES7 提案中，可以使用 ==static== 定義一個靜態屬性:
```javascript=
class Animal {
    static num = 42;
    
    constructory() {
        // ...
    }
}

console.log(Animal.num); // 42
```

# TypeScript 中類別的用法 :+1: 
## public、private 和 protected
TypeScript 可以使用三種訪問修飾符 (Access Modifiers) ，分別是 ==public==、==private== 和 ==protected==。

 - **public** 修飾的屬性或方法是公有的，可以在任何地方被訪問到，預設所有的屬性和方法都是 public 的。
 - **private** 修飾的屬性或方法是私有的，不能再宣告他的類別的外部訪問。
 - **protected** 修飾的屬性或方法是受保護的，他和 ==private== 類似，區別是他在子類別中是允許被訪問的(允許被繼承)。

> 需要注意的是，TypeScript 編譯之後的程式碼中，並沒有限制 private 屬性在外部的可及性。只是在 TypeScript 撰寫當下時會噴錯提醒你，TypeScript 只是模仿強型別語言，在當下會噴錯，但在編譯完後他==本質仍然是 JavaScript==。

## readonly
只讀屬性關鍵字，只允許出現在屬性宣告或索引簽名中。
如果和其他修飾符同時存在的話，需要寫在其後面。
```javascript=
class Animal {
    // public readonly name;
    readonly name;
    
    public constructor(name) {
        this.name = name;
    }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';

// index.ts(10,3): TS2540: Cannot assign to 'name' because it is a read-only property.
```

## 抽象類別
abstract 用於定義抽象類別和其中的抽象方法。
抽象類別是不允許被實例化的，抽象類別中的抽象方法==必須被子類別實現==。
```javascript=
abstract class Animal {
    public name;
    
    public constructor(name) {
        this.name = name;
    }
    
    public abstract sayHi();
}

let a = new Animal('Jack');
// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
```

下面是一個正確使用抽象類別的例子:
```javascript=
abstract class Animal {
    public name;
    
    public constructor(name) {
        this.name = name;
    }
    
    public abstract sayHi();
}

class Cat extends Animal {
    public sayHi() {
        console.log(`Meow, My name is ${this.name}`);
    }
}

let cat = new Cat('Tom');
cat.sayHi(); // Meow, My name is Tom
```
 > 需要注意的是，即使是抽象方法，TypeScript 的編譯結果中，仍然會存在這個類別。

## 類別的型別
給類別加上 TypeScript 的型別很簡單，與介面類似:
```javascript=
class Animal {
    name: string;
    
    constructor(name: string) {
        this.name = name;
    }
    
    sayHi(): string {
        return `My name is ${this.name}`;
    }
}

let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
```

---

參考資料來源 :
 - https://willh.gitbook.io/typescript-tutorial/advanced/class
 - https://pjchender.dev/javascript/js-oo/
 - https://www.happycoding.today/posts/49
 - [關於 Object ，一口氣全說完
](https://medium.com/enjoy-life-enjoy-coding/javascript-%E9%97%9C%E6%96%BC-object-%E4%B8%80%E5%8F%A3%E6%B0%A3%E5%85%A8%E8%AA%AA%E5%AE%8C-4bb924bcc79f)