[JavaScript] 探索 ES6 類別語法 - 類別宣告、初始化、方法定義、繼承等

JavaScript 的類別是在 ES6(ES2015) 中新引入的語法。在此之前,JavaScript 主要是透過函數和原型實現物件導向編程。但類別語法的出現,使得物件導向程式設計更為直觀和明確。

使用類別的原因與優勢

  • 直觀性:類別語法與其他物件導向語言中的類別相似,因此對開發者更為熟悉和易於理解。
  • 可重用性:利用類別和繼承可大幅增加代碼的可重用性。
  • 模組化:代碼結構更有組織且易於管理。

基本語法

類別宣告

在 JavaScript 中,類別是透過 class 關鍵字宣告的。

javascript
class Person {}

利用建構子方法進行初始化

constructor 方法是在類別實例建立時呼叫的特殊方法。通過此方法可以設置實例的初始狀態。

javascript
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

在上述代碼中, 類別具有名字和年齡兩個屬性。使用 new 關鍵字創建此類別的實例時,傳遞的名字和年齡會被設定到該實例中。

javascript
const ming = new Person('小明', 25);
console.log(ming.name);  // 小明

方法定義

在類別內部可以定義函數作為方法,這些方法可以在該類別的實例中呼叫。

javascript
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我叫${this.name},今年${this.age}歲。`);
  }
}

實例方法 vs 靜態方法

  • 實例方法:在類別實例中呼叫的方法。如上面的 介紹 方法就是一個實例方法。
  • 靜態方法:使用 static 關鍵字定義,並在類別本身中呼叫,不需要創建實例即可使用。

javascript
class Person {
  static populationCount() {
    console.log('全球有數十億人口。');
  }
}
Person.populationCount();  // 全球有數十億人口。

上面定義的 Person 類別的 introduce 方法可以這樣呼叫:

javascript
const ming = new Person('小明', 25);
ming.introduce();  // 我叫小明,今年25歲。

靜態方法 populationCount 可以直接用類別名稱呼叫,無需創建實例。

javascript
Person.populationCount();  // 全球有數十億人口。

繼承與擴展

在 JavaScript 中,類別的繼承是一種將現有類別的屬性和方法傳遞給新類別的機制。這有助於提高代碼的重用性和建立類別間的層次關係。

繼承概念解釋

在 JavaScript 中,類別繼承是使用 extends 關鍵字實現的。

javascript
class Animal {
 sound() {
    console.log('動物的叫聲');
  }
}

class Dog extends Animal {

}

通過繼承,子類別將繼承父類別的所有屬性和方法。在上述例子中,Dog 類別將繼承 Animal 類別的所有方法和屬性。

利用繼承提高代碼重用性

通過繼承,可以在父類別中定義通用的邏輯或數據結構,並只在子類別中添加特定功能或屬性,這樣可以減少代碼重複,提高開發效率和維護性。

方法覆蓋

在子類別中,可以重新定義父類別中的方法。這稱為方法覆蓋。被覆蓋的方法會替換掉父類別中的原始方法。

javascript
class Animal {
  sound() {
    console.log('動物的叫聲');
  }
}

class Dog extends Animal {
  sound() {
    console.log('汪汪');
  }
}

const puppy = new Dog();
puppy.sound();  // 汪汪

使用 Super 關鍵字調

用父類別的方法

當需要在子類別中調用父類別的同名方法時,可以使用 super 關鍵字。

javascript
class Animal {
  sound() {
    console.log('動物的叫聲');
  }
}

class Dog extends Animal {
  sound() {
    super.發出聲音();
    console.log('汪汪');
  }
}

const puppy = new Dog();
puppy.sound();  // 動物的叫聲  汪汪

建構子覆寫

在子類別中,可以覆寫父類別的建構子。但是,若在子類別的建構子中沒有呼叫super,將會產生錯誤。

使用super關鍵字於子類別的建構子中,可以呼叫父類別的建構子,進行必要的初始化工作。

javascript
class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
}

const puppy = new Dog('小狗', '貴賓犬');
console.log(puppy.name);   // 小狗
console.log(puppy.breed); // 貴賓犬

存取修飾符

在JavaScript類別中,為了限制資料和方法的存取權,會使用到存取修飾符。

Public, Private, Protected

存取修飾符用於指定類別成員(屬性和方法)的存取權限。透過此,能夠隱藏類別的內部實作,或僅對特定成員進行限制存取,確保物件導向的封裝原則。

  • Public:默認所有成員都是公開的。它可以在任何地方被存取。
  • Private:以#符號或底線(_)開頭的成員是私有的。只能在該類別內部存取。
  • Protected:目前JavaScript沒有官方的受保護存取修飾符。但使用底線(_)常被隱含地當作受保護成員。它意味著可以在該類別及其子類別中被存取。

使用底線(_)和#表示私有成員變數和方法

javascript
class 範例 {
  __protectedMember = "可以被視為受保護成員。";
  #privateMember = "這是私有變數。";

  _protectedMethod() {
    console.log("這是被視為受保護的方法。");
  }

  #privateMethod() {
    console.log("這是私有方法。");
  }
}

Getter和Setter方法

Getter和Setter方法被用於封裝對物件屬性的存取和修改。透過它們,可以安全地存取物件的內部資料或執行特定邏輯。

Getter和Setter方法的定義及使用

javascript
class Person {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }

  set name(value) {
    this._name = value;
  }
}

const ming = new Person("小明");
console.log(ming.name); // 小明
ming.name = "小芳";
console.log(ming.name); // 小芳

靜態成員

靜態成員屬於類別本身,不屬於任何實例。當需要在類別中建立共享屬性或方法時,會使用到靜態成員。

在類別層級定義靜態變數和方法

javascript
class Math {
  static PI = 3.141592;

  static circleArea(radius) {
    return this.PI * radius * radius;
  }
}

console.log(Math.PI);       // 3.141592
console.log(Math.circleArea(5)); // 約 78.5398

靜態方法與實例方法之間的差異和用途

靜態方法在類別層級調用,對於執行與實例狀態無關的操作很有用。相對地,實例方法基於物件的內部狀態運作,進行存取或修改物件資料的操作。


在JavaScript中,關於類別的各種功能對於實現物件導向編程模式非常有幫助。適當地利用這些功能可以提高代碼的重用性、擴展性和維護性。希望大家都能善用JavaScript類別的這些強大功能,進行高效的編程。


© Copyright 2023 CLONE CODING