如果你想要一个 ES5 解决方案的模拟,它非常简单;构造函数只是成为了保持闭包的东西,你可以在其中添加任何需要记住私有状态的方法/对象。
原型方法没有访问初始构造函数的闭包的权限,除非使用一些特权 getter。
class Person {
constructor ({ name, age, deepDarkSecret }) {
const bribe = () => console.log(`Give me money, or everybody will know about ${ redactRandom(deepDarkSecret) }`);
Object.assign(this, { name, age });
Object.assign(this, { bribe });
}
recallSecret () {
console.log("I'm just a prototyped method, so I know nothing about any secret, unless I use a privileged function...");
this.bribe();
}
}
如果您查看这个示例,您会注意到它与您的示例并没有太大区别(只是使用了“更干净”的小工具,特别是添加原型/静态方法)。 它仍然是在原型下面。
如果您有使用任何类型的模块/导出(ES6是理想的),那么通过另一种数据类型,您可以拥有真正的隐私而不必自己清理。
这看起来有点hackey。希望它将来会变得更加简洁,并成为更好东西的基础,但如果您想要基于实例的私有访问,即使是对于原型化的方法,请在从中导出类的模块中制作一个WeakMap。
使用this作为您的键。现在,所有原型方法都可以访问WeakMap的闭包而不是创建特权函数...
...缺点是每次想要私有变量时,都必须在WeakMap中查找它们,而不是从this中获取。
const personalBaggage = new WeakMap();
class Person {
constructor ({ name, age, darkestMoment }) {
const privates = { name, age, darkestMoment };
personalBaggage.add(this, privates);
}
recallDarkestHour () {
const { darkestMoment } = personalBaggage.get(this);
console.log(darkestMoment);
}
}
export default Person;
只要您不在
this
内部失去引用,这个方法就可以正常工作。
与使用
Symbol
不同,无论如何您都无法获得对私有对象的引用。
如果您知道对象上的符号,可以使用这些符号查找属性。
而获取任何对象上符号列表只需调用一个函数。
Symbol
不是用于保密,而是用于防止命名冲突,并定义可以在任何对象/函数上使用但不会在循环中被捕捉、被意外调用或覆盖等常见符号。
将私有数据包存储在以this
为键的弱映射中,可让您访问完全隐藏的数据集,该数据集在该模块之外是完全无法访问的。
更好的是,弱映射中的键/值不会阻止GC清理它们。
通常,如果它们留在一个数组中,那么它们将保留在那里。 如果一个对象的最后一个使用地点是作为弱映射中的键,则它会被收集并且弱映射值会自动擦除(在本机ES6中;内存奖励无法进行填充,但对象可以)。
protected
方法,而不是一个private
方法。无论如何,在ES6中旧的方式仍然有效。 - dandavis