Zunächst möchte ich klarstellen, dass dies withveraltet ist und dass die Verwendung im Allgemeinen eine schlechte Praxis ist .
Meine Frage bezieht sich jedoch auf einen Sonderfall: Verwenden eines speziellen ProxyObjekts als Parameter von with.
Hintergrund
Ich arbeite an einem Projekt, bei dem ich den Zugriff auf einen Code auf den globalen Bereich beschränken muss.
Ein Ansatz könnte darin bestehen, eine Schleife mit zu verwenden eval, die konstante Variablen mit dem Wert von undefinedfür jede Eigenschaft des globalen Objekts erstellt. Dies scheint jedoch noch schlimmer zu sein als die Verwendung withund kann den Zugriff auf mit letund erstellte Variablen nicht einschränken const.
Die Idee
Die Idee ist, ein Proxyals Argument zu verwenden with, dessen ...
hasTrap kehrt immer zurücktrue, daher können keine Suchvorgänge oder Zuweisungen über diewithAnweisung hinausgehengetTrap funktionieren normal, außer dass sieReferenceErrors auslösen, wenn sie versuchen, auf eine nicht vorhandene Variable (dh eine Eigenschaft) zuzugreifen.setTrap funktionieren normal (oder enthalten möglicherweise eine benutzerdefinierte Logik)targetObjekt hat keine[[Prototype]](dh es wurde mit erstelltObject.create(null))targetObjekt hat eine@@unscopablesEigenschaft mit dem Wert eines leeren Objekts, um das Scoping jeder Eigenschaft zu ermöglichen
Also so etwas wie dieser Code:
const scope = Object.create(null)
Object.assign(scope, {
undefined,
console,
String,
Number,
Boolean,
Array,
Object,
/* etc. */
[Symbol.unscopables]: Object.create(null)
})
const scopeProxy = new Proxy(scope, {
get: (obj, prop) => {
if (prop in obj)
return obj[prop]
else
throw new ReferenceError(`${prop} is not defined`)
},
set: Reflect.set,
has: () => true
})
with(scopeProxy) {
//Sandboxed code
foo = Number('42')
console.log(foo) //42
try{
console.log(scopeProxy) //Inaccessible
}catch(e){
console.error(e) //ReferenceError: scopeProxy is not defined
}
}
Kontras vermeiden
Auf der MDN-Seitewith sind mehrere Kontras zu der Anweisung aufgeführt , aber durch diese Verwendung werden sie jeweils entfernt.
1. Leistung
Das Problem:
Das Nachschlagen von Bezeichnern, die nicht Mitglied des
withParameterobjekts der Anweisung sind, ist weniger performant.Vermeidung:
Keine Suche kann über das Parameterobjekt hinausgehen.
2. Mehrdeutigkeit
Das Problem:
Es ist schwer zu entscheiden, welcher Bezeichner von den gleichnamigen nachgeschlagen wird.
Vermeidung:
Alle Suchvorgänge und Zuweisungen rufen die Eigenschaft des Parameterobjekts ab oder ändern sie.
3. Vorwärtskompatibilität
Das Problem:
Die Eigenschaften der Parameterobjekte oder ihre Prototypen können sich in Zukunft ändern.
Vermeidung:
Das Parameterobjekt ist anfangs leer und hat keinen Prototyp, daher können sich keine Eigenschaften ändern.
Frage
Der obige Code funktioniert einwandfrei, und die auf MDN aufgeführten Kontras gelten hierfür nicht.
Meine Frage lautet also:
Ist es immer noch eine schlechte Praxis, die withAnweisung zu verwenden, und wenn ja, welche Nachteile hat die Verwendung in diesem Fall?
withdiese Weise schlecht ist oder nicht.
withund einen Proxy ist immer noch ziemlich langsam. Ich würde versuchen, nach einer anderen Lösung für das zugrunde liegende Problem zu suchen, aber ansonsten verwenden Sie nur withein Werkzeug, das zu tun scheint, was Sie brauchen.