iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 20
1

總算來到了類別 Class(撒花~) 每天邊學邊寫 TypeScript 20天好像才來到真正的重點哈。在使用 React 函式庫進行開發時,經常會使用 ES6 中的類別(Class),因此,了解 Class 的觀念很重要。

類別(Class)基本概念

先來複習一下 Class 的觀念吧!Class 語法是 ES6 出現的,可以看作是 ES5 建構函式(constructor)的語法糖,透過 Class 可以更類似傳統物件導向語言的方式來撰寫繼承。簡單來說,Class 就是一個可以產生物件的特殊函式,可以想像成是設計圖,能透過它產生新的物件。

類別 Class 宣告

類別由三個元素組成:建構函式、屬性和方法

舉例來說:

class Car {
  description: string;
  color: string;

  constructor(color: string) {
    this.color = color;
    this.description = "我是車子" 
  }

  getDescription(): string {
    return `${this.descroption} - ${this.color}`
  }
}

const blackCar = new Car("黑色");
const redCar = new Car("紅色");
console.log(blackCar.getDescription()); // 我是車子 - 黑色

上面的程式碼用 class 語法建立一張車子的設計圖,裡面有一個建構式、description 屬性和 getDescription 方法,之後使用 new 關鍵字創建車子物件,並執行建構函式進行初始化,這時候,車子就會擁有設計圖的所有屬性和功能。而在初始化時,透過傳入不同的參數,就會讓實例有些不同,像是:上面程式碼中傳入不同顏色的參數,創造出來的車子就會是不同顏色的車子。

類別的宣告不一定要存在建構函式,但前提是此類別沒有繼承自其他的類別。

Class 擴展/繼承 - extends 關鍵字

Class 和 Interface 一樣都可以使用 extends 關鍵字進行擴展/繼承。假設現在車子要開發第二代,希望提供消費者不同空間大小車型的選擇,但仍維持第一代的功能,這時候就可以這樣做:

class CarV2 extends Car{
    getDescription(): string {
    return `${super.getDescription()} 第二代強化版`;
  }
}

const greenCar = new CarV2('綠色');
console.log(greenCar.getDescription()) //我是車子 - 綠色 第二代強化版
console.log(greenCar.color) //綠色

可以發現,新增的 CarV2 裡面,沒有原本在 Car 類別內的屬性 color,但執行調用卻可以使用,就是因為使用了 extends 定義了 CarV2 的原型為 Car 的緣故。

透過 extends關鍵字,新類別 CarV2 指定了原型為 Car,這時候 CarV2 會指向 Car,因而可以取用 Car 的屬性和方法。此時,繼承的 CarV2 又稱子類別,而被繼承的 Car 則是父類別。

值得注意的是,CarV2 從他老爸 Car 繼承所有的方法和屬性,且在類別內只要透過 super 就能穿越父子間的羈絆,直接請老爸幫忙執行事情,就像上方的 super.getDescription ,就是直接請老爸執行他的 getDescription。

另外,在 CarV2 沒有建構函式,為什麼呢?上面有提到建構函式不一定需要,預設會是空函式(即 function() {}),通常只有需要進行初始化成員變數才需要建構函式。

但如果父類別和子類別同時需要在建構函式中定義的屬性,就需要使用 super 傳入父類別需要的值:

class Car {
  description: string;
  color: string;

  constructor(color: string) {
    this.color = color;
    this.description = "我是車子" 
  }

  getDescription(): string {
    return `${this.description} - ${this.color}`
  }
}



class CarV2 extends Car{
constructor(color: string, version: number) {
    // 在這裡執行的 super 等同於父類別的 constructor
    super(color);
    this.version = version;
  }
    version: number;
    getDescription(): string {
    return `${super.getDescription()} ${this.version} 第二代強化版`;
  }
}

const greenCar = new CarV2('綠色', 23);
console.log(greenCar.getDescription())//我是車子 - 綠色 23 第二代強化版

這時候,建構函式中的參數一定要被註記,因為函式的型別參數推論預設都是 any 。

理解到這邊,覺得類別似乎跟昨天介紹的介面有部分相似,介面和類別都是屬於基礎物件型別,都可以做擴展/繼承,但是兩者很重要的差別是介面是抽象的,只能用來定義格式,無法實作;而類別除了宣告屬性外,也可以描述出物件的行為和實例化成物件。

小結

今天簡單的介紹了 TS 中的類別基本用法和繼承概念,明天繼續探討Class。


上一篇
【Day 19】TypeScript 介面(Interface) v.s. 型別別名(Type Alias)
下一篇
【Day 21】TypeScript 類別 -存取修飾符(Access Modifiers)、抽象( Abstract)
系列文
Typescript 初心者手札30

尚未有邦友留言

立即登入留言