使用类管理私有数据

使用类最常见的障碍之一是找到处理私有状态的正确方法。处理私有状态有 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); 
        };
    }
}