多項提案擴充了現有的 JavaScript 類別語法,並新增功能。本文說明 V8 v7.2 和 Chrome 72 中的新公開類別欄位語法,以及即將推出的私有類別欄位語法。
以下是一個建立名為 IncreasingCounter
類別的實例的程式碼範例
const counter = new IncreasingCounter();
counter.value;
// logs 'Getting the current value!'
// → 0
counter.increment();
counter.value;
// logs 'Getting the current value!'
// → 1
請注意,存取 value
會在傳回結果之前執行一些程式碼(例如,記錄訊息)。現在請自問,你會如何使用 JavaScript 實作這個類別?🤔
ES2015 類別語法 #
以下說明如何使用 ES2015 類別語法實作 IncreasingCounter
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
類別會在原型上安裝 value
getter 和 increment
方法。更有趣的是,類別有一個會建立實例屬性 _count
並將其預設值設定為 0
的建構函式。我們目前傾向使用底線開頭來表示 _count
不應由類別的使用者直接使用,但這只是一個慣例;它並非具有語言強制執行特殊語意的「私有」屬性。
const counter = new IncreasingCounter();
counter.value;
// logs 'Getting the current value!'
// → 0
// Nothing stops people from reading or messing with the
// `_count` instance property. 😢
counter._count;
// → 0
counter._count = 42;
counter.value;
// logs 'Getting the current value!'
// → 42
公開類別欄位 #
新的公開類別欄位語法讓我們可以簡化類別定義
class IncreasingCounter {
_count = 0;
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
_count
屬性現在可以很清楚地宣告在類別的最上方。我們不再需要建構函式來定義一些欄位。太棒了!
但是,_count
欄位仍然是一個公開屬性。在這個特定的範例中,我們希望防止使用者直接存取該屬性。
私有類別欄位 #
這時就需要用到私有類別欄位了。新的私有欄位語法類似於公開欄位,但 你可以使用 #
將欄位標記為私有。你可以將 #
視為欄位名稱的一部分
class IncreasingCounter {
#count = 0;
get value() {
console.log('Getting the current value!');
return this.#count;
}
increment() {
this.#count++;
}
}
私有欄位無法在類別主體之外存取
const counter = new IncreasingCounter();
counter.#count;
// → SyntaxError
counter.#count = 42;
// → SyntaxError
公開與私有靜態屬性 #
類別欄位語法也可以用來建立公開與私有靜態屬性和方法
class FakeMath {
// `PI` is a static public property.
static PI = 22 / 7; // Close enough.
// `#totallyRandomNumber` is a static private property.
static #totallyRandomNumber = 4;
// `#computeRandomNumber` is a static private method.
static #computeRandomNumber() {
return FakeMath.#totallyRandomNumber;
}
// `random` is a static public method (ES2015 syntax)
// that consumes `#computeRandomNumber`.
static random() {
console.log('I heard you like random numbers…');
return FakeMath.#computeRandomNumber();
}
}
FakeMath.PI;
// → 3.142857142857143
FakeMath.random();
// logs 'I heard you like random numbers…'
// → 4
FakeMath.#totallyRandomNumber;
// → SyntaxError
FakeMath.#computeRandomNumber();
// → SyntaxError
更簡單的子類別化 #
當處理會新增欄位的子類別時,類別欄位語法的優點會變得更明顯。想像下列基本類別Animal
class Animal {
constructor(name) {
this.name = name;
}
}
若要建立會新增其他執行個體屬性的Cat
子類別,您以前必須呼叫super()
來執行Animal
基本類別的建構函式,才能建立屬性
class Cat extends Animal {
constructor(name) {
super(name);
this.likesBaths = false;
}
meow() {
console.log('Meow!');
}
}
這只是為了表示貓咪不喜歡洗澡,卻需要這麼多樣板程式碼。幸運的是,類別欄位語法消除了對整個建構函式的需求,包括令人尷尬的super()
呼叫
class Cat extends Animal {
likesBaths = false;
meow() {
console.log('Meow!');
}
}
功能支援 #
支援公開類別欄位 #
支援私人類別欄位 #
支援私人方法和存取器 #
- Chrome: 自版本 84 開始支援
- Firefox: 自版本 90 開始支援
- Safari: 已支援
- Node.js: 自版本 14.6.0 開始支援
- Babel: 已支援