作者:Dr. Axel Rauschmayer
譯者:前端小智
來源:2ality
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
Ron Buckton 提出的 ECMAScript 提案 "類靜態初始化塊"已進入第四階段,計劃納入ECMAScript 2022。
為了建立一個類的例項,在JavaScript中有兩個結構:
- 欄位:建立(可選擇初始化)例項屬性。
- 建構函式:在 setup 完成之前執行的程式碼塊。
對於類的靜態部分的設定,我們只有靜態欄位。ECMAScript建議為類引入靜態初始化塊,大致上,它對靜態類的作用就像建構函式對例項的作用。
1.為什麼我們需要類中的靜態塊?
在設定靜態欄位時,使用外部函式通常也可以很好地工作:
class Translator {
static translations = {
yes: 'ja',
no: 'nein',
maybe: 'vielleicht',
};
static englishWords = extractEnglish(this.translations);
static germanWords = extractGerman(this.translations);
}
function extractEnglish(translations) {
return Object.keys(translations);
}
function extractGerman(translations) {
return Object.values(translations);
}
使用外部函式 extractEnglish()
和 extractGerman()
在這種情況下效果很好,因為我們可以看到它們是從類內部呼叫的,而且它們完全獨立於類。
如果我們想同時設定兩個靜態欄位,事情就變得不那麼優雅。
class Translator {
static translations = {
yes: 'ja',
no: 'nein',
maybe: 'vielleicht',
};
static englishWords = [];
static germanWords = [];
static _ = initializeTranslator( // (A)
this.translations, this.englishWords, this.germanWords);
}
function initializeTranslator(translations, englishWords, germanWords) {
for (const [english, german] of Object.entries(translations)) {
englishWords.push(english);
germanWords.push(german);
}
}
這一次,有幾個問題。
- 呼叫
initializeTranslator()
是一個額外的步驟,要麼在建立類之後,在類之外執行。或者通過一個變通方法來執行(A行)。 initializeTranslator()
不能訪問Translator
的私有資料。
通過提出的靜態塊(A行),我們有更優雅的解決方案。
class Translator {
static translations = {
yes: 'ja',
no: 'nein',
maybe: 'vielleicht',
};
static englishWords = [];
static germanWords = [];
static { // (A)
for (const [english, german] of Object.entries(this.translations)) {
this.englishWords.push(english);
this.germanWords.push(german);
}
}
}
2.一個更復雜的例子
在JavaScript中實現列舉的一種方法是通過帶有輔助功能的超類Enum
class Enum {
static collectStaticFields() {
// Static methods are not enumerable and thus ignored
this.enumKeys = Object.keys(this);
}
}
class ColorEnum extends Enum {
static red = Symbol('red');
static green = Symbol('green');
static blue = Symbol('blue');
static _ = this.collectStaticFields(); // (A)
static logColors() {
for (const enumKey of this.enumKeys) { // (B)
console.log(enumKey);
}
}
}
ColorEnum.logColors();
// Output:
// 'red'
// 'green'
// 'blue'
我們需要收集靜態欄位,以便我們可以遍歷列舉項的鍵(B行)。這是在建立所有靜態欄位之後的最後一步。我們再次使用一個變通方法(A行),靜態塊會更優雅。
3.詳情
靜態塊的具體內容相對來說是合乎邏輯的(相比之下,例項成員的規則更為複雜):
- 每個類可以有一個以上的靜態塊。
- 靜態塊的執行是與靜態欄位初始化器的執行交錯進行的。
- 超類的靜態成員在子類的靜態成員之前被執行。
下面的程式碼展示了這些規則:
class SuperClass {
static superField1 = console.log('superField1');
static {
assert.equal(this, SuperClass);
console.log('static block 1 SuperClass');
}
static superField2 = console.log('superField2');
static {
console.log('static block 2 SuperClass');
}
}
class SubClass extends SuperClass {
static subField1 = console.log('subField1');
static {
assert.equal(this, SubClass);
console.log('static block 1 SubClass');
}
static subField2 = console.log('subField2');
static {
console.log('static block 2 SubClass');
}
}
// Output:
// 'superField1'
// 'static block 1 SuperClass'
// 'superField2'
// 'static block 2 SuperClass'
// 'subField1'
// 'static block 1 SubClass'
// 'subField2'
// 'static block 2 SubClass'
4.在引擎中支援類靜態塊
- V8: unflagged in v9.4.146 (source)
- SpiderMonkey: behind a flag in v92, intent to ship unflagged in v93 (source)
- TypeScript: v4.4 (source)
5.JS 是否變得太像Java和/或一塌糊塗?
這是一個很小的功能,不會與其他功能競爭。我們已經可以通過 static _ = ...
的欄位來執行靜態程式碼。靜態塊意味著這種變通方法不再需要了。
除此之外,類只是JavaScript程式設計師腰帶上的眾多工具之一。我們中的一些人使用它,另一些人不使用它,而且有許多替代方案。即使是使用類的 JS 程式碼,也經常使用函式,而且往往是輕量級的。
6.總結
類靜態塊是一個相對簡單的功能,它完善了類的靜態功能。粗略來說,它是例項建構函式的靜態版本。它主要在我們需要設定一個以上的靜態欄位時有用。
~完,我是刷碗智,勵志等退休後,要回家擺地攤的人,我們下期見!
程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug。
原文:https://2ality.com/2021/09/cl...
交流
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。