JavaScript
TypeScript
private field
TS3.8
TypeScript 私有類別屬性 (Private Class Fields)
2020/09/01 15:27:33
1
2076
在 JavaScript,class 屬性預設都是 public
即使在 TypeScript, 使用者仍可透過 work-around 的方式,存取有 private 關鍵字修飾的屬性
如以下這段 TypeScript:
class Foo {
private bar = "private";
}
let instance = new Foo();
console.log(instance["bar"]); // work-around
console.log(instance.bar); // Error in compile time
// error: Property 'bar' is private and only accessible within class 'Foo'.
而現在,JS 提供新的方式定義 private field
如類別屬性,名稱需前綴 #,且需先宣告後使用,並無法從 class 外部存取
如以下這段 JS:
class B {
#hello; // private field
constructor() {
this.#hello = "hello";
this.#none = "none"; // Syntax error
}
hello() {
console.log(this.#hello);
}
}
let b = new B();
b.hello();
console.log(b.#hello === "hello"); // Syntax error
而 TypeScript 在 3.8 開始支援使用 JS private fields
需要注意以下幾點:
- 如以上提及,屬性名稱需前綴 #
- 每個 private field 存在範圍只在所擁有的 class 中 ("Every private field name is uniquely scoped to its containing class") (以下補充說明)
- 只可在所屬的 class 中存取使用到,無法透過其他 JS 方式於 class 外部存取
- 不可與 public、private 修飾關鍵字一併使用
在以下繼承關係的類別中,可以各自擁有相同名稱的 private field,並不會被 override
相對使用 private 修飾詞時,則不可重複定義
會出現 Types have separate declarations of a private property 的錯誤
class A {
#foo = 2;
bar = 3;
showFooA() {
console.log(this.#foo);
}
showBarA() {
console.log(this.bar);
}
}
class B extends A {
#foo = 4;
bar = 5;
showFooB() {
console.log(this.#foo);
}
showBarB() {
console.log(this.bar);
}
}
let b = new B();
// `this.#foo` refers to different property within each class
b.showFooA(); // 2
b.showFooB(); // 4
// `this.bar` refers to the same property
b.showBarA(); // 5
b.showBarB(); // 5
最後,
要在 TypeScript 使用 private fields 的話,需要指定 compiler target 為 ES2015 或以上
這與底層的實作方式有關,而使用 private 修飾詞定義的方式則可於所有 target 環境使用