Signatur
Beschreibung
Die with-Anweisung erweitert die Scope-Kette für eine Anweisung.
Es gibt zwei Arten von Bezeichnern: einen qualifizierten und einen unqualifizierten Bezeichner. Ein unqualifizierter Bezeichner gibt nicht an, woher er stammt.
Normalerweise wird ein unqualifizierter Bezeichner aufgelöst, indem die Scope-Kette nach einer Variablen mit diesem Namen durchsucht wird, während ein qualifizierter Bezeichner aufgelöst wird, indem die prototype-Kette eines Objekts nach einer Eigenschaft mit diesem Namen durchsucht wird.
Eine Ausnahme davon ist das global object, das an der Spitze der Scope-Kette steht und dessen Eigenschaften automatisch zu globalen Variablen werden, die ohne Qualifizierer referenziert werden können.
Die with-Anweisung fügt das angegebene Objekt während der Auswertung ihres Anweisungskörpers an den Anfang dieser Scope-Kette ein. Jeder unqualifizierte Name wird zunächst innerhalb des Objekts (über eine in-Prüfung) gesucht, bevor in der oberen Scope-Kette gesucht wird.
Beachten Sie, dass, wenn die unqualifizierte Referenz auf eine Methode des Objekts verweist, die Methode mit dem Objekt als this-Wert aufgerufen wird.
Das Objekt kann eine [Symbol.unscopables]-Eigenschaft besitzen, die eine Liste von Eigenschaften definiert, die nicht zur Scope-Kette hinzugefügt werden sollen (zur Abwärtskompatibilität). Weitere Informationen finden Sie in der Symbol.unscopables-Dokumentation.
Zu den Gründen für die Verwendung einer with-Anweisung gehören das Einsparen einer temporären Variablen und das Reduzieren der Dateigröße durch Vermeidung wiederholter langer Objektreferenzen. Es gibt jedoch weitaus mehr Gründe, warum with-Anweisungen nicht wünschenswert sind:
- Performance: Die
with-Anweisung zwingt dazu, das angegebene Objekt bei allen Namensauflösungen zuerst zu durchsuchen. Daher werden alle Bezeichner, die keine Mitglieder des angegebenen Objekts sind, in einemwith-Block langsamer gefunden. Außerdem kann der Optimizer keine Annahmen darüber treffen, worauf sich jeder unqualifizierte Bezeichner bezieht, sodass er bei jeder Verwendung des Bezeichners dieselbe property lookup wiederholen muss. - Lesbarkeit: Die
with-Anweisung erschwert es einem menschlichen Leser oder JavaScript-Compiler zu entscheiden, ob ein unqualifizierter Name entlang der Scope-Kette gefunden wird, und wenn ja, in welchem Objekt. Wenn Sie sich nur die Definition vonfansehen, ist es unmöglich zu sagen, worauf sich dasximwith-Körper bezieht. Erst wennfaufgerufen wird, kannxalso.xoder als erster formaler Parameter vonfbestimmt werden. Wenn Sie vergessen,xim Objekt zu definieren, das Sie als zweiten Parameter übergeben, erhalten Sie keinen Fehler — stattdessen erhalten Sie einfach unerwartete Ergebnisse. Es ist auch unklar, was die eigentliche Absicht eines solchen Codes wäre. - Forward-Kompatibilität: Code, der
withverwendet, ist möglicherweise nicht vorwärtskompatibel, insbesondere wenn er mit etwas anderem als einem einfachen Objekt verwendet wird, das in Zukunft weitere Eigenschaften erhalten kann. Wenn Sie z.B.f([1, 2, 3], obj)in einer ECMAScript 5-Umgebung aufrufen, wird dievalues-Referenz innerhalb derwith-Anweisung zuobjaufgelöst. ECMAScript 2015 führt jedoch einevalues-Eigenschaft aufArray.prototypeein (so dass sie auf jedem Array verfügbar sein wird). Nach dem Upgrade der Umgebung wird dievalues-Referenz innerhalb derwith-Anweisung stattdessen zu[1, 2, 3].valuesaufgelöst und verursacht wahrscheinlich Fehler. In diesem speziellen Beispiel istvaluesüberArray.prototype[Symbol.unscopables]als unscopable definiert, sodass es immer noch korrekt zumvalues-Parameter aufgelöst wird. Wäre es nicht als unscopable definiert, wäre dies ein schwer zu debuggendes Problem.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $expression Pflicht | expression | — | Fügt den angegebenen Ausdruck zur Scope-Kette hinzu, die bei der Auswertung der Anweisung verwendet wird. Die Klammern um den Ausdruck sind erforderlich. |
| $statement Pflicht | statement | — | Jede beliebige Anweisung. Um mehrere Anweisungen auszuführen, verwenden Sie eine block-Anweisung ({ ... }), um diese Anweisungen zu gruppieren. |
Rückgabewert
with-Statement hat keinen Rückgabewert; es ist eine Kontrollfluss-Anweisung.Beispiele
Verwendung der with-Anweisung
let a, x, y;
const r = 10;
with (Math) {
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}
Vermeiden der with-Anweisung durch Destrukturierung von Eigenschaften in den aktuellen Scope
let a, x, y;
const r = 10;
{
const { PI, cos, sin } = Math;
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}
Vermeiden der with-Anweisung durch Verwendung eines IIFE
const objectHavingAnEspeciallyLengthyName = { foo: true, bar: false };
if (((o) => o.foo && !o.bar)(objectHavingAnEspeciallyLengthyName)) {
// Dieser Zweig wird ausgeführt.
}
Erstellen dynamischer Namespaces mit der with-Anweisung und einem Proxy
const namespace = new Proxy(
{},
{
has(target, key) {
// Vermeide das Abfangen globaler Eigenschaften wie `console`
if (key in globalThis) {
return false;
}
// Fange alle property lookups ab
return true;
},
get(target, key) {
return key;
},
},
);
with (namespace) {
console.log(a, b, c); // "a" "b" "c"
}