Zunächst möchte ich klarstellen, dass dies with
veraltet ist und dass die Verwendung im Allgemeinen eine schlechte Praxis ist .
Meine Frage bezieht sich jedoch auf einen Sonderfall: Verwenden eines speziellen Proxy
Objekts 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 undefined
für jede Eigenschaft des globalen Objekts erstellt. Dies scheint jedoch noch schlimmer zu sein als die Verwendung with
und kann den Zugriff auf mit let
und erstellte Variablen nicht einschränken const
.
Die Idee
Die Idee ist, ein Proxy
als Argument zu verwenden with
, dessen ...
has
Trap kehrt immer zurücktrue
, daher können keine Suchvorgänge oder Zuweisungen über diewith
Anweisung hinausgehenget
Trap funktionieren normal, außer dass sieReferenceError
s auslösen, wenn sie versuchen, auf eine nicht vorhandene Variable (dh eine Eigenschaft) zuzugreifen.set
Trap funktionieren normal (oder enthalten möglicherweise eine benutzerdefinierte Logik)target
Objekt hat keine[[Prototype]]
(dh es wurde mit erstelltObject.create(null)
)target
Objekt hat eine@@unscopables
Eigenschaft 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
with
Parameterobjekts 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 with
Anweisung zu verwenden, und wenn ja, welche Nachteile hat die Verwendung in diesem Fall?
with
diese Weise schlecht ist oder nicht.with
und 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 nurwith
ein Werkzeug, das zu tun scheint, was Sie brauchen.Antworten:
Klingt nach dem guten alten lexikalischen und dynamischen Thema. Im Allgemeinen ist der lexikalische Bereich sicherer, aber in einigen Situationen ist ein dynamischer Bereich sinnvoll, da er einige Lösungen sehr vereinfacht. Ich würde sagen, Ihr Beispiel ist einer der Fälle, in denen es nützlich sein kann.
quelle