描述
定義類
類實際上是“特殊的函式”,就像你可以定義函式表示式和函式宣告一樣,類可以透過兩種方式定義:類表示式或類宣告。
// Declaration
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// Expression; the class is anonymous but assigned to a variable
const Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
// Expression; the class has its own name
const Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
與函式表示式類似,類表示式可以是匿名的,或者擁有一個不同於其賦值變數的名稱。然而,與函式宣告不同,類宣告與 let 或 const 具有相同的暫時死區限制,並且行為表現為不會被提升。
類體
類的身體是花括號 {} 中的部分。你可以在這裡定義類成員,例如方法或建構函式。
即使沒有 "use strict" 指令,類體也會在嚴格模式下執行。
類元素可以從三個方面進行描述:
- 種類:Getter、setter、方法或欄位
- 位置:靜態或例項
- 可見性:公共或私有
它們共同構成了 16 種可能的組合。為了更邏輯地劃分參考資料並避免內容重疊,不同的元素在不同的頁面中詳細介紹。
- 方法定義
-
公共例項方法
- getter
-
公共例項 getter
- setter
-
公共例項 setter
- 公共類欄位
-
公共例項欄位
static-
公共靜態方法、getter、setter 和欄位
- 私有元素
-
所有私有元素
注意:私有元素有一個限制,即在同一個類中宣告的所有私有名稱都必須是唯一的。所有其他公共屬性沒有這個限制——你可以有多個同名的公共屬性,最後一個會覆蓋其他的。這與物件初始化器中的行為相同。
此外,還有兩種特殊的類元素語法:constructor 和靜態初始化塊,它們有各自的引用。
建構函式
constructor 方法是用於建立和初始化類建立的物件的特殊方法。在一個類中只能有一個名為“constructor”的特殊方法——如果類中包含多個 constructor 方法,則會丟擲 SyntaxError。
建構函式可以使用 super 關鍵字呼叫超類的建構函式。
你可以在建構函式中建立例項屬性
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
或者,如果你的例項屬性值不依賴於建構函式的引數,你可以將它們定義為類欄位。
靜態初始化塊
靜態初始化塊允許對靜態屬性進行靈活初始化,包括在初始化期間評估語句,同時授予訪問私有作用域的許可權。
可以宣告多個靜態塊,並且這些塊可以與靜態欄位和方法的宣告交錯(所有靜態項都按宣告順序進行評估)。
方法
方法在每個類例項的原型上定義,並由所有例項共享。方法可以是普通函式、非同步函式、生成器函式或非同步生成器函式。有關更多資訊,請參閱方法定義。
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
*getSides() {
yield this.height;
yield this.width;
yield this.height;
yield this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
console.log([...square.getSides()]); // [10, 10, 10, 10]
靜態方法和欄位
static 關鍵字為類定義靜態方法或欄位。靜態屬性(欄位和方法)定義在類本身上,而不是每個例項上。靜態方法通常用於為應用程式建立實用函式,而靜態欄位則適用於快取、固定配置或任何不需要在例項之間複製的資料。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static displayName = "Point";
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined
console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
欄位宣告
使用類欄位宣告語法,建構函式的示例可以寫成:
class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
類欄位類似於物件屬性,而不是變數,因此我們不使用諸如 const 等關鍵字來宣告它們。在 JavaScript 中,私有元素使用特殊的識別符號語法,因此也不應使用 public 和 private 等修飾符關鍵字。
如上所示,欄位可以帶或不帶預設值宣告。沒有預設值的欄位預設為 undefined。透過提前宣告欄位,類定義變得更具自解釋性,並且欄位始終存在,這有助於最佳化。
有關更多資訊,請參閱公共類欄位。
私有元素
使用私有欄位,定義可以如下完善。
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
從類外部引用私有欄位是錯誤的;它們只能在類體內部讀取或寫入。透過定義類外部不可見的內容,你可以確保類的使用者不會依賴於內部實現,這些內部實現可能會因版本而異。
私有欄位只能在欄位宣告中提前宣告。它們不能像普通屬性那樣透過賦值稍後建立。
私有方法和訪問器也可以使用與其公共對應項相同的語法定義,但識別符號以 # 開頭。
有關更多資訊,請參閱私有元素。
繼承
extends 關鍵字用於類宣告或類表示式,以建立作為另一個建構函式(類或函式)子類的類。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}
speak() {
console.log(`${this.name} barks.`);
}
}
const d = new Dog("Mitzie");
d.speak(); // Mitzie barks.
如果子類中存在建構函式,它需要先呼叫 super(),然後才能使用 this。super 關鍵字也可以用於呼叫超類的相應方法。
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(`${this.name} roars.`);
}
}
const l = new Lion("Fuzzy");
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
評估順序
當class 宣告或class 表示式被評估時,其各個元件按照以下順序進行評估:
- 如果存在
extends子句,則首先進行評估。它必須評估為一個有效的建構函式或null,否則會丟擲TypeError。 constructor方法被提取,如果constructor不存在,則用預設實現替換。然而,由於constructor定義只是一個方法定義,此步驟不可觀察。- 類元素的屬性鍵按宣告順序進行評估。如果屬性鍵是計算得出的,則計算表示式將被評估,其
this值設定為圍繞該類的this值(而不是類本身)。此時所有屬性值都尚未被評估。 - 方法和訪問器按宣告順序安裝。例項方法和訪問器安裝在當前類的
prototype屬性上,靜態方法和訪問器安裝在類本身上。私有例項方法和訪問器被儲存以供稍後直接安裝在例項上。此步驟不可觀察。 - 類現在已使用
extends指定的原型和constructor指定的實現進行初始化。對於以上所有步驟,如果一個評估的表示式試圖訪問類的名稱,則會丟擲ReferenceError,因為類尚未初始化。 - 類元素的值按宣告順序進行評估
- 類現在已完全初始化,可以作為建構函式使用。
有關例項如何建立,請參閱constructor參考。
示例
使用例項和靜態方法繫結 this
當靜態方法或例項方法在沒有 this 值的情況下被呼叫時,例如透過將方法賦值給一個變數然後呼叫它,方法內部的 this 值將是 undefined。即使沒有 "use strict" 指令,這種行為也是相同的,因為 class 主體中的程式碼總是以嚴格模式執行。
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
const obj = new Animal();
obj.speak(); // the Animal object
const speak = obj.speak;
speak(); // undefined
Animal.eat(); // class Animal
const eat = Animal.eat;
eat(); // undefined
如果我們使用傳統的基於函式的語法在非嚴格模式下重寫上述內容,那麼 this 方法呼叫會自動繫結到 globalThis。在嚴格模式下,this 的值保持為 undefined。
function Animal() {}
Animal.prototype.speak = function () {
return this;
};
Animal.eat = function () {
return this;
};
const obj = new Animal();
const speak = obj.speak;
speak(); // global object (in non–strict mode)
const eat = Animal.eat;
eat(); // global object (in non-strict mode)
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-class-definitions |
瀏覽器相容性
載入中…