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