使用類管理私有資料
使用類最常見的障礙之一是找到處理私有狀態的正確方法。處理私有狀態有 4 種常見解決方案:
使用符號
符號是 ES2015 中引入的新原始型別,如 MDN 中所定義
符號是唯一且不可變的資料型別,可用作物件屬性的識別符號。
使用符號作為屬性鍵時,它不可列舉。
因此,他們不會使用 for var in
或 Object.keys
透露。
因此,我們可以使用符號來儲存私人資料。
const topSecret = Symbol('topSecret'); // our private key; will only be accessible on the scope of the module file
export class SecretAgent{
constructor(secret){
this[topSecret] = secret; // we have access to the symbol key (closure)
this.coverStory = 'just a simple gardner';
this.doMission = () => {
figureWhatToDo(topSecret[topSecret]); // we have access to topSecret
};
}
}
由於 symbols
是唯一的,我們必須參考原始符號來訪問私有屬性。
import {SecretAgent} from 'SecretAgent.js'
const agent = new SecretAgent('steal all the ice cream');
// ok lets try to get the secret out of him!
Object.keys(agent); // ['coverStory'] only cover story is public, our secret is kept.
agent[Symbol('topSecret')]; // undefined, as we said, symbols are always unique, so only the original symbol will help us to get the data.
但它並非 100%私密; 讓我們打破那個經紀人! 我們可以使用 Object.getOwnPropertySymbols
方法來獲取物件符號。
const secretKeys = Object.getOwnPropertySymbols(agent);
agent[secretKeys[0]] // 'steal all the ice cream' , we got the secret.
使用 WeakMaps
WeakMap
是為 es6 新增的一種新型別的物件。
如 MDN 上所定義
WeakMap 物件是鍵/值對的集合,其中鍵被弱引用。鍵必須是物件,值可以是任意值。
如在 MDN 上所定義的,WeakMap
的另一個重要特徵是。
WeakMap 中的關鍵是弱的。這意味著,如果沒有對金鑰的其他強引用,整個條目將由垃圾收集器從 WeakMap 中刪除。
我們的想法是使用 WeakMap 作為整個類的靜態對映,將每個例項儲存為鍵,並將私有資料儲存為該例項鍵的值。
因此,只有在課堂內我們才能訪問 WeakMap
系列。
讓我們的代理人嘗試一下,與 WeakMap
:
const topSecret = new WeakMap(); // will hold all private data of all instances.
export class SecretAgent{
constructor(secret){
topSecret.set(this,secret); // we use this, as the key, to set it on our instance private data
this.coverStory = 'just a simple gardner';
this.doMission = () => {
figureWhatToDo(topSecret.get(this)); // we have access to topSecret
};
}
}
因為 topSecret
常量是在我們的模組閉包中定義的,並且因為我們沒有將它繫結到我們的例項屬性,所以這種方法完全是私有的,我們無法訪問代理 topSecret
。
定義建構函式中的所有方法
這裡的想法只是在建構函式中定義所有方法和成員,並使用閉包來訪問私有成員而不將它們分配給 this
。
export class SecretAgent{
constructor(secret){
const topSecret = secret;
this.coverStory = 'just a simple gardner';
this.doMission = () => {
figureWhatToDo(topSecret); // we have access to topSecret
};
}
}
在這個例子中,資料是 100%私有的,不能在課外到達,所以我們的代理是安全的。
使用命名約定
我們將決定任何私有屬性將以 _
為字首。
請注意,對於此方法,資料並非真正私有。
export class SecretAgent{
constructor(secret){
this._topSecret = secret; // it private by convention
this.coverStory = 'just a simple gardner';
this.doMission = () => {
figureWhatToDo(this_topSecret);
};
}
}