使用類管理私有資料

使用類最常見的障礙之一是找到處理私有狀態的正確方法。處理私有狀態有 4 種常見解決方案:

使用符號

符號是 ES2015 中引入的新原始型別,如 MDN 中所定義

符號是唯一且不可變的資料型別,可用作物件屬性的識別符號。

使用符號作為屬性鍵時,它不可列舉。

因此,他們不會使用 for var inObject.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); 
        };
    }
}