在 2015 年,ECMAScript 6 (ES6) 標準引入了類別。這篇文章將教你如何使用類別。

JavaScript 有一種相對不常見的方式來實現繼承:原型繼承。雖然我認為原型繼承是很好的一種方式,但它與其他流行的程式語言實現的繼承方式不同,後者是基於類別的。

來自於 Java、Python 或其他語言的人很難理解原型繼承的細節,因此 ECMAScript 委員會決定在原型繼承的基礎上添加糖衣語法,使其類似於其他流行語言中基於類別的繼承方式。

重要的是:JavaScript 在底層仍然保持相同,你仍然可以以正常的方式訪問對象原型。

類別定義

以下是一個類別的示例:

class Person {
 constructor(name) {
 this.name = name
 }

 hello() {
 return 'Hello, I am ' + this.name + '.'
 }
}

類別有一個識別符,我們可以使用 new ClassIdentifier() 來創建新對象。

當對象被初始化時,將調用 constructor 方法,並傳入任何參數。

類別可以有任意數量的方法。在這個例子中,hello 是一個方法,可以在所有由這個類別派生的對象上調用:

const flavio = new Person('Flavio')
flavio.hello()

類別繼承

一個類別可以繼承另一個類別,在使用該類別初始化的對象將繼承兩個類別的所有方法。

如果被繼承的類別和繼承的類別中有同樣名稱的方法,最近的方法將優先執行:

class Programmer extends Person {
 hello() {
 return super.hello() + ' I am a programmer.'
 }
}

const flavio = new Programmer('Flavio')
flavio.hello()

(上述程式碼輸出:「Hello, I am Flavio. I am a programmer.」)

類別中並沒有顯式的類別變數聲明,但你必須在構造函數中初始化任何變數。

在類別內部,你可以使用 super() 調用父類。

靜態方法

通常方法是定義在實例上的,而不是定義在類上的。

靜態方法在類上執行:

class Person {
 static genericHello() {
 return 'Hello'
 }
}

Person.genericHello() // Hello

私有方法

JavaScript 沒有內建的方式來定義私有或受保護的方法。

雖然有解決方法,但這裡不會進一步討論。

存取器

你可以添加以 getset 為前綴的方法,來創建一個 getter 和 setter。當你訪問變量時,或者修改其值時,這兩個不同的程式碼塊將被執行。

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

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

 get name() {
 return this._name
 }
}

如果只有 getter,該屬性將無法設置,任何對該屬性的設置嘗試(除了在構造函數中初始化該類的新對象時)都將被忽略:

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

 get name() {
 return this._name
 }
}

如果只有 setter,你可以更改值,但無法從外部訪問:

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

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

存取器非常有用,當你想在更改屬性值時執行一些代碼,或者當你想創建一個「計算」屬性時。你可以使用 getter 修改返回的值。

你也可以在值更改時運行一些代碼,比如將日誌記錄到控制台或文件中。