Baseline 已廣泛支援

此特性已經非常成熟,並且適用於許多裝置和瀏覽器版本。自 2016 年 3 月以來,它已在所有瀏覽器中可用。

類是用於建立物件的模板。它們將資料與處理該資料的程式碼封裝在一起。JS 中的類構建於原型之上,但也具有一些類特有的語法和語義。

有關更多示例和解釋,請參閱使用類指南。

描述

定義類

類實際上是“特殊的函式”,就像你可以定義函式表示式函式宣告一樣,類可以透過兩種方式定義:類表示式類宣告

js
// 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;
  }
};

與函式表示式類似,類表示式可以是匿名的,或者擁有一個不同於其賦值變數的名稱。然而,與函式宣告不同,類宣告與 letconst 具有相同的暫時死區限制,並且行為表現為不會被提升

類體

類的身體是花括號 {} 中的部分。你可以在這裡定義類成員,例如方法或建構函式。

即使沒有 "use strict" 指令,類體也會在嚴格模式下執行。

類元素可以從三個方面進行描述:

  • 種類:Getter、setter、方法或欄位
  • 位置:靜態或例項
  • 可見性:公共或私有

它們共同構成了 16 種可能的組合。為了更邏輯地劃分參考資料並避免內容重疊,不同的元素在不同的頁面中詳細介紹。

方法定義

公共例項方法

getter

公共例項 getter

setter

公共例項 setter

公共類欄位

公共例項欄位

static

公共靜態方法、getter、setter 和欄位

私有元素

所有私有元素

注意:私有元素有一個限制,即在同一個類中宣告的所有私有名稱都必須是唯一的。所有其他公共屬性沒有這個限制——你可以有多個同名的公共屬性,最後一個會覆蓋其他的。這與物件初始化器中的行為相同。

此外,還有兩種特殊的類元素語法:constructor靜態初始化塊,它們有各自的引用。

建構函式

constructor 方法是用於建立和初始化類建立的物件的特殊方法。在一個類中只能有一個名為“constructor”的特殊方法——如果類中包含多個 constructor 方法,則會丟擲 SyntaxError

建構函式可以使用 super 關鍵字呼叫超類的建構函式。

你可以在建構函式中建立例項屬性

js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

或者,如果你的例項屬性值不依賴於建構函式的引數,你可以將它們定義為類欄位

靜態初始化塊

靜態初始化塊允許對靜態屬性進行靈活初始化,包括在初始化期間評估語句,同時授予訪問私有作用域的許可權。

可以宣告多個靜態塊,並且這些塊可以與靜態欄位和方法的宣告交錯(所有靜態項都按宣告順序進行評估)。

方法

方法在每個類例項的原型上定義,並由所有例項共享。方法可以是普通函式、非同步函式、生成器函式或非同步生成器函式。有關更多資訊,請參閱方法定義

js
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 關鍵字為類定義靜態方法或欄位。靜態屬性(欄位和方法)定義在類本身上,而不是每個例項上。靜態方法通常用於為應用程式建立實用函式,而靜態欄位則適用於快取、固定配置或任何不需要在例項之間複製的資料。

js
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

欄位宣告

使用類欄位宣告語法,建構函式的示例可以寫成:

js
class Rectangle {
  height = 0;
  width;
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

類欄位類似於物件屬性,而不是變數,因此我們不使用諸如 const 等關鍵字來宣告它們。在 JavaScript 中,私有元素使用特殊的識別符號語法,因此也不應使用 publicprivate 等修飾符關鍵字。

如上所示,欄位可以帶或不帶預設值宣告。沒有預設值的欄位預設為 undefined。透過提前宣告欄位,類定義變得更具自解釋性,並且欄位始終存在,這有助於最佳化。

有關更多資訊,請參閱公共類欄位

私有元素

使用私有欄位,定義可以如下完善。

js
class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
}

從類外部引用私有欄位是錯誤的;它們只能在類體內部讀取或寫入。透過定義類外部不可見的內容,你可以確保類的使用者不會依賴於內部實現,這些內部實現可能會因版本而異。

私有欄位只能在欄位宣告中提前宣告。它們不能像普通屬性那樣透過賦值稍後建立。

私有方法和訪問器也可以使用與其公共對應項相同的語法定義,但識別符號以 # 開頭。

有關更多資訊,請參閱私有元素

繼承

extends 關鍵字用於類宣告類表示式,以建立作為另一個建構函式(類或函式)子類的類。

js
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(),然後才能使用 thissuper 關鍵字也可以用於呼叫超類的相應方法。

js
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 表示式被評估時,其各個元件按照以下順序進行評估:

  1. 如果存在 extends 子句,則首先進行評估。它必須評估為一個有效的建構函式或 null,否則會丟擲 TypeError
  2. constructor 方法被提取,如果 constructor 不存在,則用預設實現替換。然而,由於 constructor 定義只是一個方法定義,此步驟不可觀察。
  3. 類元素的屬性鍵按宣告順序進行評估。如果屬性鍵是計算得出的,則計算表示式將被評估,其 this 值設定為圍繞該類的 this 值(而不是類本身)。此時所有屬性值都尚未被評估。
  4. 方法和訪問器按宣告順序安裝。例項方法和訪問器安裝在當前類的 prototype 屬性上,靜態方法和訪問器安裝在類本身上。私有例項方法和訪問器被儲存以供稍後直接安裝在例項上。此步驟不可觀察。
  5. 類現在已使用 extends 指定的原型和 constructor 指定的實現進行初始化。對於以上所有步驟,如果一個評估的表示式試圖訪問類的名稱,則會丟擲 ReferenceError,因為類尚未初始化。
  6. 類元素的值按宣告順序進行評估
    • 對於每個例項欄位(公共或私有),其初始化表示式被儲存。初始化器在例項建立期間,在建構函式開始時(對於基類)或在 super() 呼叫返回之前(對於派生類)立即進行評估。
    • 對於每個靜態欄位(公共或私有),其初始化器在 this 設定為類本身的情況下進行評估,並且該屬性在類上建立。
    • 靜態初始化塊this 設定為類本身的情況下進行評估。
  7. 類現在已完全初始化,可以作為建構函式使用。

有關例項如何建立,請參閱constructor參考。

示例

使用例項和靜態方法繫結 this

當靜態方法或例項方法在沒有 this 值的情況下被呼叫時,例如透過將方法賦值給一個變數然後呼叫它,方法內部的 this 值將是 undefined。即使沒有 "use strict" 指令,這種行為也是相同的,因為 class 主體中的程式碼總是以嚴格模式執行。

js
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

js
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

瀏覽器相容性

另見