How does JavaScript emulate private
members? Back
As we all know, the proposal of private
instance fields in classes has been pushed towards stage 4 since ES2022. It means that we can define private members inside classes like other OOP languages, which are limited to access outside a class in user code.
How does JavaScript emulate such behaviour? Use WeakMap
. For why? The MDN document has given us the answer:
- Compared to a
Map
, aWeakMap
does not hold strong references to the object used as the key, so the metadata shares the same lifetime as the object itself, avoiding memory leaks. Compared to using non-enumerable and/or
Symbol
properties, aWeakMap
is external to the object and there is no way for user code to retrieve the metadata through reflective methods likeObject.getOwnPropertySymbols
.class A { constructor() { this[Symbol('#private')] = 'unreachable value?'; } } // we can access it actually: const a = new A(); a[Object.getOwnPropertySymbols(a)[0]]; // => "unreachable value?"
Compared to a closure, the same
WeakMap
can be reused for all instances created from a constructor, making it more memory-efficient, and allowing different instances of the same class to read the private members of each other.
The detailed implementation when the runtime environment does not support the proposal:
const A = (function () {
// use a closure to ensure that the weak map cannot be accessed outside the class A
const privates = new WeakMap();
return class {
constructor() {
privates.set(this, {['#private'] : 'unreachable value?'});
}
getPrivateValue() {
return privates.get(this)['#private'];
}
}
})();
const a = new A();
// the private member can only be accessed via an exposed method
a.getPrivateValue(); // => "unreachable value?"
As the plugin is integrated with a code management system like GitLab or GitHub, you may have to auth with your account before leaving comments around this article.
Notice: This plugin has used Cookie to store your token with an expiration.