Abgesehen von den gegebenen Antworten können Sie auch einen Proxy verwenden, um "private Eigenschaften" zu erstellen, indem Sie nur den Proxy für den öffentlichen Code verfügbar machen. Die Instanz ist nur für den Konstruktor, gebundene Methoden und den Proxy selbst als receiver
verfügbar.
Dies hat einige Vorteile gegenüber der Verwendung von Symbolen und WeakMaps.
- Symbole sind aufzählbar und können von einem Proxy erfasst werden.
- WeakMaps versagen, wenn die Instanz als
instance !== new Proxy(instance)
proxiziert wird.
Scheitern von WeakMap z.B.
const map = new WeakMap()
const instance = new SomeClass()
map.set(instance, 'foo')
// Irgendwo auf dem Weg im Code eines Drittanbieters
const proxy = new Proxy(instance, {})
assert(map.set(instance) === map.get(proxy)) // scheitern
const proxy2 = new Proxy(proxy, {})
// mehr Kopfschmerzen
Verwendung eines Proxy, um eine Instanz mit privaten Eigenschaften zu validieren
getProxy = (instance) => new Proxy(instance, {
get: (target, name, receiver) => {
console.log('get', { target, name, receiver })
if (name[0] === '_') throw new Error('Kann nicht auf private Eigenschaft ' + name + ' zugreifen')
return Reflect.get(target, name, receiver)
},
set: (target, name, value, receiver) => {
console.log('set', { target, name, value, receiver })
if (name[0] === '_') throw new Error('Kann den privaten Wert ' + name + ' nicht setzen')
return Reflect.set(target, name, value, receiver)
}
})
class PublicClass {
constructor() {
Object.defineProperty(this, '_privateProp', { enumerable: false, writable: true, configurable: false })
return getProxy(this) // kann als Dekorator ausgelagert werden
}
getPrivatePropFail() {
return this._privateProp // fehlerhaft
}
getPrivateProp = () => {
return this._privateProp // okay
}
setPrivateProp = (value) => {
return this._privateProp = value // okay
}
}
pub = new PublicClass()
try {
console.log('get pub._privateProp', pub._privateProp)
} catch(e) {
console.error(e)
}
try {
console.log('set pub._privateProp', pub._privateProp = 'Sie versagen')
} catch(e) {
console.error(e)
}
pub.setPrivateProp('Sie okay')
console.log('pub.getPrivateProp()', pub.getPrivateProp())
console.log('pub', Object.keys(pub))
Die Vorteile dieses Ansatzes
- Die Validierung des Zugriffs auf private Eigenschaften ist dekoriert (optional) auf der Instanz.
- Die privaten Eigenschaften sind im Konsolen-, Debugging- und Testumgebungen inspizierbar und einfache Eigenschaften (keine Symbole oder Maps)
- Sie kontrollieren die Validierung und Fehlerbehandlung
Die Nachteile
- Der Proxy fügt Overhead und eine Abstraktionsebene hinzu
- Das Debuggen zeigt den Proxy(), der das Objekt umgibt
- Methoden, die auf private Eigenschaften zugreifen, müssen Pfeilfunktionen sein
- Sie können die privaten Eigenschaften versehentlich preisgeben, wenn Sie die Instanz durch das Hinzufügen einer Methode
getSelf = () => this
Anmerkungen:
Aufgrund des Overheads könnte diese Methode in Szenarien verwendet werden, in denen die Eigenschaftskapselung und die Klarheit des Debuggens den Overhead überwiegen. Zum Beispiel beim Befüllen von Modellen aus dem Speicher. z.B. model.setJSON(json)
würde sicherstellen, dass keine privaten Eigenschaften verunstaltet werden.
Diese Methode kann weiter angepasst werden, um eine bessere Kapselung zu bieten, indem eine WeakMap zusammen mit dem Proxy verwendet wird, um sicherzustellen, dass "private" Eigenschaften nicht sichtbar sind, aber der Zugriff auf die WeakMap mit derselben Instanz in jedem Bereich ermöglicht wird. Dies geht jedoch zulasten der Lesbarkeit und des Debuggens.